azuki 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +71 -0
  3. data/bin/azuki +17 -0
  4. data/data/cacert.pem +3988 -0
  5. data/lib/azuki.rb +17 -0
  6. data/lib/azuki/auth.rb +339 -0
  7. data/lib/azuki/cli.rb +38 -0
  8. data/lib/azuki/client.rb +764 -0
  9. data/lib/azuki/client/azuki_postgresql.rb +141 -0
  10. data/lib/azuki/client/cisaurus.rb +26 -0
  11. data/lib/azuki/client/pgbackups.rb +113 -0
  12. data/lib/azuki/client/rendezvous.rb +108 -0
  13. data/lib/azuki/client/ssl_endpoint.rb +25 -0
  14. data/lib/azuki/command.rb +294 -0
  15. data/lib/azuki/command/account.rb +23 -0
  16. data/lib/azuki/command/accounts.rb +34 -0
  17. data/lib/azuki/command/addons.rb +305 -0
  18. data/lib/azuki/command/apps.rb +393 -0
  19. data/lib/azuki/command/auth.rb +86 -0
  20. data/lib/azuki/command/base.rb +230 -0
  21. data/lib/azuki/command/certs.rb +209 -0
  22. data/lib/azuki/command/config.rb +137 -0
  23. data/lib/azuki/command/db.rb +218 -0
  24. data/lib/azuki/command/domains.rb +85 -0
  25. data/lib/azuki/command/drains.rb +46 -0
  26. data/lib/azuki/command/fork.rb +164 -0
  27. data/lib/azuki/command/git.rb +64 -0
  28. data/lib/azuki/command/help.rb +179 -0
  29. data/lib/azuki/command/keys.rb +115 -0
  30. data/lib/azuki/command/labs.rb +147 -0
  31. data/lib/azuki/command/logs.rb +45 -0
  32. data/lib/azuki/command/maintenance.rb +61 -0
  33. data/lib/azuki/command/pg.rb +269 -0
  34. data/lib/azuki/command/pgbackups.rb +329 -0
  35. data/lib/azuki/command/plugins.rb +110 -0
  36. data/lib/azuki/command/ps.rb +232 -0
  37. data/lib/azuki/command/regions.rb +22 -0
  38. data/lib/azuki/command/releases.rb +124 -0
  39. data/lib/azuki/command/run.rb +180 -0
  40. data/lib/azuki/command/sharing.rb +89 -0
  41. data/lib/azuki/command/ssl.rb +43 -0
  42. data/lib/azuki/command/stack.rb +62 -0
  43. data/lib/azuki/command/status.rb +51 -0
  44. data/lib/azuki/command/update.rb +47 -0
  45. data/lib/azuki/command/version.rb +23 -0
  46. data/lib/azuki/deprecated.rb +5 -0
  47. data/lib/azuki/deprecated/help.rb +38 -0
  48. data/lib/azuki/distribution.rb +9 -0
  49. data/lib/azuki/excon.rb +9 -0
  50. data/lib/azuki/helpers.rb +517 -0
  51. data/lib/azuki/helpers/azuki_postgresql.rb +165 -0
  52. data/lib/azuki/helpers/log_displayer.rb +70 -0
  53. data/lib/azuki/plugin.rb +163 -0
  54. data/lib/azuki/updater.rb +171 -0
  55. data/lib/azuki/version.rb +3 -0
  56. data/lib/vendor/azuki/okjson.rb +598 -0
  57. data/spec/azuki/auth_spec.rb +256 -0
  58. data/spec/azuki/client/azuki_postgresql_spec.rb +71 -0
  59. data/spec/azuki/client/pgbackups_spec.rb +43 -0
  60. data/spec/azuki/client/rendezvous_spec.rb +62 -0
  61. data/spec/azuki/client/ssl_endpoint_spec.rb +48 -0
  62. data/spec/azuki/client_spec.rb +564 -0
  63. data/spec/azuki/command/addons_spec.rb +601 -0
  64. data/spec/azuki/command/apps_spec.rb +351 -0
  65. data/spec/azuki/command/auth_spec.rb +38 -0
  66. data/spec/azuki/command/base_spec.rb +109 -0
  67. data/spec/azuki/command/certs_spec.rb +178 -0
  68. data/spec/azuki/command/config_spec.rb +144 -0
  69. data/spec/azuki/command/db_spec.rb +110 -0
  70. data/spec/azuki/command/domains_spec.rb +87 -0
  71. data/spec/azuki/command/drains_spec.rb +34 -0
  72. data/spec/azuki/command/fork_spec.rb +56 -0
  73. data/spec/azuki/command/git_spec.rb +144 -0
  74. data/spec/azuki/command/help_spec.rb +93 -0
  75. data/spec/azuki/command/keys_spec.rb +120 -0
  76. data/spec/azuki/command/labs_spec.rb +100 -0
  77. data/spec/azuki/command/logs_spec.rb +60 -0
  78. data/spec/azuki/command/maintenance_spec.rb +51 -0
  79. data/spec/azuki/command/pg_spec.rb +236 -0
  80. data/spec/azuki/command/pgbackups_spec.rb +307 -0
  81. data/spec/azuki/command/plugins_spec.rb +104 -0
  82. data/spec/azuki/command/ps_spec.rb +195 -0
  83. data/spec/azuki/command/releases_spec.rb +130 -0
  84. data/spec/azuki/command/run_spec.rb +83 -0
  85. data/spec/azuki/command/sharing_spec.rb +59 -0
  86. data/spec/azuki/command/stack_spec.rb +46 -0
  87. data/spec/azuki/command/status_spec.rb +48 -0
  88. data/spec/azuki/command/version_spec.rb +16 -0
  89. data/spec/azuki/command_spec.rb +211 -0
  90. data/spec/azuki/helpers/azuki_postgresql_spec.rb +155 -0
  91. data/spec/azuki/helpers_spec.rb +48 -0
  92. data/spec/azuki/plugin_spec.rb +172 -0
  93. data/spec/azuki/updater_spec.rb +44 -0
  94. data/spec/helper/legacy_help.rb +16 -0
  95. data/spec/spec.opts +1 -0
  96. data/spec/spec_helper.rb +224 -0
  97. data/spec/support/display_message_matcher.rb +49 -0
  98. data/spec/support/openssl_mock_helper.rb +8 -0
  99. metadata +211 -0
@@ -0,0 +1,307 @@
1
+ require "spec_helper"
2
+ require "azuki/command/pgbackups"
3
+
4
+ module Azuki::Command
5
+ describe Pgbackups do
6
+ before do
7
+ @pgbackups = prepare_command(Pgbackups)
8
+ @pgbackups.azuki.stub!(:info).and_return({})
9
+
10
+ api.post_app("name" => "example")
11
+ api.put_config_vars(
12
+ "example",
13
+ {
14
+ "DATABASE_URL" => "postgres://database",
15
+ "AZUKI_POSTGRESQL_IVORY" => "postgres://database",
16
+ "PGBACKUPS_URL" => "https://ip:password@pgbackups.azukiapp.com/client"
17
+ }
18
+ )
19
+ @pgbackups.stub :app_attachments => mock_attachments
20
+ end
21
+
22
+ let(:mock_attachments) {
23
+ [
24
+ Azuki::Helpers::AzukiPostgresql::Attachment.new({
25
+ 'config_var' => 'AZUKI_POSTGRESQL_IVORY',
26
+ 'resource' => {'name' => 'softly-mocking-123',
27
+ 'value' => 'postgres://database',
28
+ 'type' => 'azuki-postgresql:baku' }})
29
+ ]
30
+ }
31
+
32
+ after do
33
+ api.delete_app("example")
34
+ end
35
+
36
+ it "requests a pgbackups transfer list for the index command" do
37
+ stub_core
38
+ stub_pgbackups.get_transfers.returns([{
39
+ "created_at" => "2012-01-01 12:00:00 +0000",
40
+ "started_at" => "2012-01-01 12:00:01 +0000",
41
+ "from_name" => "DATABASE",
42
+ "size" => "1024",
43
+ "progress" => "dump 2048",
44
+ "to_name" => "BACKUP",
45
+ "to_url" => "s3://bucket/userid/b001.dump"
46
+ }])
47
+
48
+ stderr, stdout = execute("pgbackups")
49
+ stderr.should == ""
50
+ stdout.should == <<-STDOUT
51
+ ID Backup Time Status Size Database
52
+ ---- ------------------------- --------- ---- --------
53
+ b001 2012-01-01 12:00:00 +0000 Capturing 1024 DATABASE
54
+ STDOUT
55
+ end
56
+
57
+ describe "single backup" do
58
+ let(:from_name) { "FROM_NAME" }
59
+ let(:from_url) { "postgres://from/bar" }
60
+ let(:attachment) { double('attachment', :display_name => from_name, :url => from_url ) }
61
+ before do
62
+ @pgbackups.stub!(:hpg_resolve).and_return(attachment)
63
+ end
64
+
65
+ it "gets the url for the latest backup if nothing is specified" do
66
+ stub_core
67
+ stub_pgbackups.get_latest_backup.returns({"public_url" => "http://latest/backup.dump"})
68
+
69
+ old_stdout_isatty = STDOUT.isatty
70
+ $stdout.stub!(:isatty).and_return(true)
71
+ stderr, stdout = execute("pgbackups:url")
72
+ stderr.should == ""
73
+ stdout.should == <<-STDOUT
74
+ http://latest/backup.dump
75
+ STDOUT
76
+ $stdout.stub!(:isatty).and_return(old_stdout_isatty)
77
+ end
78
+
79
+ it "gets the url for the named backup if a name is specified" do
80
+ stub_pgbackups.get_backup.with("b001").returns({"public_url" => "http://latest/backup.dump" })
81
+
82
+ old_stdout_isatty = STDOUT.isatty
83
+ $stdout.stub!(:isatty).and_return(true)
84
+ stderr, stdout = execute("pgbackups:url b001")
85
+ stderr.should == ""
86
+ stdout.should == <<-STDOUT
87
+ http://latest/backup.dump
88
+ STDOUT
89
+ $stdout.stub!(:isatty).and_return(old_stdout_isatty)
90
+ end
91
+
92
+ it "should capture a backup when requested" do
93
+ backup_obj = {'to_url' => "s3://bucket/userid/b001.dump"}
94
+
95
+ @pgbackups.stub!(:args).and_return([])
96
+ @pgbackups.stub!(:transfer!).with(from_url, from_name, nil, "BACKUP", {:expire => nil}).and_return(backup_obj)
97
+ @pgbackups.stub!(:poll_transfer!).with(backup_obj).and_return(backup_obj)
98
+
99
+ @pgbackups.capture
100
+ end
101
+
102
+ it "should send expiration flag to client if specified on args" do
103
+ backup_obj = {'to_url' => "s3://bucket/userid/b001.dump"}
104
+
105
+ @pgbackups.stub!(:options).and_return({:expire => true})
106
+ @pgbackups.stub!(:transfer!).with(from_url, from_name, nil, "BACKUP", {:expire => true}).and_return(backup_obj)
107
+ @pgbackups.stub!(:poll_transfer!).with(backup_obj).and_return(backup_obj)
108
+
109
+ @pgbackups.capture
110
+ end
111
+
112
+ it "destroys no backup without a name" do
113
+ stub_core
114
+ stderr, stdout = execute("pgbackups:destroy")
115
+ stderr.should == <<-STDERR
116
+ ! Usage: azuki pgbackups:destroy BACKUP_ID
117
+ ! Must specify BACKUP_ID to destroy.
118
+ STDERR
119
+ stdout.should == ""
120
+ end
121
+
122
+ it "destroys a backup" do
123
+ stub_core
124
+ stub_pgbackups.get_backup("b001").returns({})
125
+ stub_pgbackups.delete_backup("b001").returns({})
126
+
127
+ stderr, stdout = execute("pgbackups:destroy b001")
128
+ stderr.should == ""
129
+ stdout.should == <<-STDOUT
130
+ Destroying b001... done
131
+ STDOUT
132
+ end
133
+
134
+ it "aborts if no database addon is present" do
135
+ api.delete_config_var("example", "DATABASE_URL")
136
+ stub_core
137
+ stderr, stdout = execute("pgbackups:capture")
138
+ stderr.should == <<-STDERR
139
+ ! Your app has no databases.
140
+ STDERR
141
+ stdout.should == ""
142
+ end
143
+
144
+ context "on errors" do
145
+ def stub_failed_capture(log)
146
+ @backup_obj = {
147
+ "error_at" => Time.now.to_s,
148
+ "finished_at" => Time.now.to_s,
149
+ "log" => log,
150
+ 'to_url' => 'postgres://from/bar'
151
+ }
152
+ stub_core
153
+ stub_pgbackups.create_transfer.returns(@backup_obj)
154
+ stub_pgbackups.get_transfer.returns(@backup_obj)
155
+
156
+ any_instance_of(Azuki::Command::Pgbackups) do |pgbackups|
157
+ stub(pgbackups).app_attachments.returns(
158
+ mock_attachments
159
+ )
160
+ end
161
+ end
162
+
163
+ it 'aborts on a generic error' do
164
+ stub_failed_capture "something generic"
165
+ stderr, stdout = execute("pgbackups:capture")
166
+ stderr.should == <<-STDERR
167
+ ! An error occurred and your backup did not finish.
168
+ ! Please run `azuki logs --ps pgbackups` for details.
169
+ STDERR
170
+ stdout.should == <<-STDOUT
171
+
172
+ AZUKI_POSTGRESQL_IVORY (DATABASE_URL) ----backup---> bar
173
+
174
+ \r\e[0K... 0 -
175
+ STDOUT
176
+ end
177
+
178
+ it 'aborts and informs when the database isnt up yet' do
179
+ stub_failed_capture 'could not translate host name "ec2-42-42-42-42.compute-1.amazonaws.com" to address: Name or service not known'
180
+ stderr, stdout = execute("pgbackups:capture")
181
+ stderr.should == <<-STDERR
182
+ ! An error occurred and your backup did not finish.
183
+ ! Please run `azuki logs --ps pgbackups` for details.
184
+ ! The database is not yet online. Please try again.
185
+ STDERR
186
+ stdout.should == <<-STDOUT
187
+
188
+ AZUKI_POSTGRESQL_IVORY (DATABASE_URL) ----backup---> bar
189
+
190
+ \r\e[0K... 0 -
191
+ STDOUT
192
+ end
193
+
194
+ it 'aborts and informs when the credentials are incorrect' do
195
+ stub_failed_capture 'psql: FATAL: database "randomname" does not exist'
196
+ stderr, stdout = execute("pgbackups:capture")
197
+ stderr.should == <<-STDERR
198
+ ! An error occurred and your backup did not finish.
199
+ ! Please run `azuki logs --ps pgbackups` for details.
200
+ ! The database credentials are incorrect.
201
+ STDERR
202
+ stdout.should == <<-STDOUT
203
+
204
+ AZUKI_POSTGRESQL_IVORY (DATABASE_URL) ----backup---> bar
205
+
206
+ \r\e[0K... 0 -
207
+ STDOUT
208
+ end
209
+ end
210
+ end
211
+
212
+ context "restore" do
213
+ let(:attachment) { double('attachment', :display_name => 'someconfigvar', :url => 'postgres://fromhost/database') }
214
+ before do
215
+ from_name, from_url = "FROM_NAME", "postgres://fromhost/database"
216
+
217
+ @pgbackups_client = mock("pgbackups_client")
218
+ @pgbackups.stub!(:pgbackup_client).and_return(@pgbackups_client)
219
+ end
220
+
221
+ it "should receive a confirm_command on restore" do
222
+ @pgbackups_client.stub!(:get_latest_backup).and_return({"to_url" => "s3://bucket/user/bXXX.dump"})
223
+
224
+ @pgbackups.should_receive(:confirm_command).and_return(false)
225
+ @pgbackups_client.should_not_receive(:transfer!)
226
+
227
+ @pgbackups.restore
228
+ end
229
+
230
+ it "aborts if no database addon is present" do
231
+ @pgbackups.should_receive(:hpg_resolve).and_raise(SystemExit)
232
+ lambda { @pgbackups.restore }.should raise_error(SystemExit)
233
+ end
234
+
235
+ context "for commands which perform restores" do
236
+ before do
237
+ @backup_obj = {
238
+ "to_name" => "TO_NAME",
239
+ "to_url" => "s3://bucket/userid/bXXX.dump",
240
+ "from_url" => "FROM_NAME",
241
+ "from_name" => "postgres://databasehost/dbname"
242
+ }
243
+
244
+ @pgbackups.stub!(:confirm_command).and_return(true)
245
+ @pgbackups_client.should_receive(:create_transfer).and_return(@backup_obj)
246
+ @pgbackups.stub!(:poll_transfer!).and_return(@backup_obj)
247
+ end
248
+
249
+ it "should default to the latest backup" do
250
+ @pgbackups.stub(:args).and_return([])
251
+ @pgbackups_client.should_receive(:get_latest_backup).and_return(@backup_obj)
252
+ @pgbackups.restore
253
+ end
254
+
255
+
256
+ it "should restore the named backup" do
257
+ name = "backupname"
258
+ args = ['DATABASE', name]
259
+ @pgbackups.stub(:args).and_return(args)
260
+ @pgbackups.stub(:shift_argument).and_return(*args)
261
+ @pgbackups.stub(:hpg_resolve).and_return(attachment)
262
+ @pgbackups_client.should_receive(:get_backup).with(name).and_return(@backup_obj)
263
+ @pgbackups.restore
264
+ end
265
+
266
+ it "should handle external restores" do
267
+ args = ['db_name_gets_shifted_out_in_resolve_db', 'http://external/file.dump']
268
+ @pgbackups.stub(:args).and_return(args)
269
+ @pgbackups.stub(:shift_argument).and_return(*args)
270
+ @pgbackups.stub(:hpg_resolve).and_return(attachment)
271
+ @pgbackups_client.should_not_receive(:get_backup)
272
+ @pgbackups_client.should_not_receive(:get_latest_backup)
273
+ @pgbackups.restore
274
+ end
275
+ end
276
+
277
+ context "on errors" do
278
+ before(:each) do
279
+ @pgbackups_client.stub!(:get_latest_backup).and_return({"to_url" => "s3://bucket/user/bXXX.dump"})
280
+ @pgbackups.stub!(:confirm_command).and_return(true)
281
+ end
282
+
283
+ def stub_error_backup_with_log(log)
284
+ @backup_obj = {
285
+ "error_at" => Time.now.to_s,
286
+ "log" => log
287
+ }
288
+
289
+ @pgbackups_client.should_receive(:create_transfer).and_return(@backup_obj)
290
+ @pgbackups.stub!(:poll_transfer!).and_return(@backup_obj)
291
+ end
292
+
293
+ it 'aborts for a generic error' do
294
+ stub_error_backup_with_log 'something generic'
295
+ @pgbackups.should_receive(:error).with("An error occurred and your restore did not finish.\nPlease run `azuki logs --ps pgbackups` for details.")
296
+ @pgbackups.restore
297
+ end
298
+
299
+ it 'aborts and informs for expired s3 urls' do
300
+ stub_error_backup_with_log 'Invalid dump format: /tmp/aDMyoXPrAX/b031.dump: XML document text'
301
+ @pgbackups.should_receive(:error).with { |message| message.should =~ /backup url is invalid/ }
302
+ @pgbackups.restore
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
@@ -0,0 +1,104 @@
1
+ require "spec_helper"
2
+ require "azuki/command/plugins"
3
+
4
+ module Azuki::Command
5
+ include SandboxHelper
6
+
7
+ describe Plugins do
8
+
9
+ before do
10
+ @plugin = Azuki::Plugin.new("git://github.com/azuki/Plugin.git")
11
+ end
12
+
13
+ context("install") do
14
+
15
+ before do
16
+ Azuki::Plugin.should_receive(:new).with('git://github.com/azuki/Plugin.git').and_return(@plugin)
17
+ @plugin.should_receive(:install).and_return(true)
18
+ end
19
+
20
+ it "installs plugins" do
21
+ Azuki::Plugin.should_receive(:load_plugin).and_return(true)
22
+ stderr, stdout = execute("plugins:install git://github.com/azuki/Plugin.git")
23
+ stderr.should == ""
24
+ stdout.should == <<-STDOUT
25
+ Installing Plugin... done
26
+ STDOUT
27
+ end
28
+
29
+ it "does not install plugins that do not load" do
30
+ Azuki::Plugin.should_receive(:load_plugin).and_return(false)
31
+ @plugin.should_receive(:uninstall).and_return(true)
32
+ stderr, stdout = execute("plugins:install git://github.com/azuki/Plugin.git")
33
+ stderr.should == '' # normally would have error, but mocks/stubs don't allow
34
+ stdout.should == "Installing Plugin... " # also inaccurate, would end in ' failed'
35
+ end
36
+
37
+ end
38
+
39
+ context("uninstall") do
40
+
41
+ before do
42
+ Azuki::Plugin.should_receive(:new).with('Plugin').and_return(@plugin)
43
+ end
44
+
45
+ it "uninstalls plugins" do
46
+ @plugin.should_receive(:uninstall).and_return(true)
47
+ stderr, stdout = execute("plugins:uninstall Plugin")
48
+ stderr.should == ""
49
+ stdout.should == <<-STDOUT
50
+ Uninstalling Plugin... done
51
+ STDOUT
52
+ end
53
+
54
+ it "does not uninstall plugins that do not exist" do
55
+ stderr, stdout = execute("plugins:uninstall Plugin")
56
+ stderr.should == <<-STDERR
57
+ ! Plugin plugin not found.
58
+ STDERR
59
+ stdout.should == <<-STDOUT
60
+ Uninstalling Plugin... failed
61
+ STDOUT
62
+ end
63
+
64
+ end
65
+
66
+ context("update") do
67
+
68
+ before do
69
+ Azuki::Plugin.should_receive(:new).with('Plugin').and_return(@plugin)
70
+ end
71
+
72
+ it "updates plugin by name" do
73
+ @plugin.should_receive(:update).and_return(true)
74
+ stderr, stdout = execute("plugins:update Plugin")
75
+ stderr.should == ""
76
+ stdout.should == <<-STDOUT
77
+ Updating Plugin... done
78
+ STDOUT
79
+ end
80
+
81
+ it "updates all plugins" do
82
+ Azuki::Plugin.should_receive(:list).and_return([], [], ['Plugin'])
83
+ @plugin.should_receive(:update).and_return(true)
84
+ stderr, stdout = execute("plugins:update")
85
+ stderr.should == ""
86
+ stdout.should == <<-STDOUT
87
+ Updating Plugin... done
88
+ STDOUT
89
+ end
90
+
91
+ it "does not update plugins that do not exist" do
92
+ stderr, stdout = execute("plugins:update Plugin")
93
+ stderr.should == <<-STDERR
94
+ ! Plugin plugin not found.
95
+ STDERR
96
+ stdout.should == <<-STDOUT
97
+ Updating Plugin... failed
98
+ STDOUT
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,195 @@
1
+ require "spec_helper"
2
+ require "azuki/command/ps"
3
+
4
+ describe Azuki::Command::Ps do
5
+
6
+ before(:each) do
7
+ stub_core
8
+ end
9
+
10
+ context("cedar") do
11
+
12
+ before(:each) do
13
+ api.post_app("name" => "example", "stack" => "cedar")
14
+ end
15
+
16
+ after(:each) do
17
+ api.delete_app("example")
18
+ end
19
+
20
+ it "ps:dynos errors out on cedar apps" do
21
+ lambda { execute("ps:dynos") }.should raise_error(Azuki::Command::CommandFailed, "For Cedar apps, use `azuki ps`")
22
+ end
23
+
24
+ it "ps:workers errors out on cedar apps" do
25
+ lambda { execute("ps:workers") }.should raise_error(Azuki::Command::CommandFailed, "For Cedar apps, use `azuki ps`")
26
+ end
27
+
28
+ describe "ps" do
29
+
30
+ it "displays processes" do
31
+ Azuki::Command::Ps.any_instance.should_receive(:time_ago).exactly(10).times.and_return("2012/09/11 12:34:56 (~ 0s ago)")
32
+ api.post_ps_scale('example', 'web', 10)
33
+ stderr, stdout = execute("ps")
34
+ stderr.should == ""
35
+ stdout.should == <<-STDOUT
36
+ === web: `bundle exec thin start -p $PORT`
37
+ web.1: created 2012/09/11 12:34:56 (~ 0s ago)
38
+ web.2: created 2012/09/11 12:34:56 (~ 0s ago)
39
+ web.3: created 2012/09/11 12:34:56 (~ 0s ago)
40
+ web.4: created 2012/09/11 12:34:56 (~ 0s ago)
41
+ web.5: created 2012/09/11 12:34:56 (~ 0s ago)
42
+ web.6: created 2012/09/11 12:34:56 (~ 0s ago)
43
+ web.7: created 2012/09/11 12:34:56 (~ 0s ago)
44
+ web.8: created 2012/09/11 12:34:56 (~ 0s ago)
45
+ web.9: created 2012/09/11 12:34:56 (~ 0s ago)
46
+ web.10: created 2012/09/11 12:34:56 (~ 0s ago)
47
+
48
+ STDOUT
49
+ end
50
+
51
+ it "displays one-off processes" do
52
+ Azuki::Command::Ps.any_instance.should_receive(:time_ago).and_return('2012/09/11 12:34:56 (~ 0s ago)', '2012/09/11 12:34:56 (~ 0s ago)')
53
+ api.post_ps "example", "bash"
54
+
55
+ stderr, stdout = execute("ps")
56
+ stderr.should == ""
57
+ stdout.should == <<-STDOUT
58
+ === run: one-off processes
59
+ run.1: created 2012/09/11 12:34:56 (~ 0s ago): `bash`
60
+
61
+ === web: `bundle exec thin start -p $PORT`
62
+ web.1: created 2012/09/11 12:34:56 (~ 0s ago)
63
+
64
+ STDOUT
65
+ end
66
+
67
+ end
68
+
69
+ describe "ps:restart" do
70
+
71
+ it "restarts all processes with no args" do
72
+ stderr, stdout = execute("ps:restart")
73
+ stderr.should == ""
74
+ stdout.should == <<-STDOUT
75
+ Restarting processes... done
76
+ STDOUT
77
+ end
78
+
79
+ it "restarts one process" do
80
+ stderr, stdout = execute("ps:restart web.1")
81
+ stderr.should == ""
82
+ stdout.should == <<-STDOUT
83
+ Restarting web.1 process... done
84
+ STDOUT
85
+ end
86
+
87
+ it "restarts a type of process" do
88
+ stderr, stdout = execute("ps:restart web")
89
+ stderr.should == ""
90
+ stdout.should == <<-STDOUT
91
+ Restarting web processes... done
92
+ STDOUT
93
+ end
94
+
95
+ end
96
+
97
+ describe "ps:scale" do
98
+
99
+ it "can scale using key/value format" do
100
+ stderr, stdout = execute("ps:scale web=5")
101
+ stderr.should == ""
102
+ stdout.should == <<-STDOUT
103
+ Scaling web processes... done, now running 5
104
+ STDOUT
105
+ end
106
+
107
+ it "can scale relative amounts" do
108
+ stderr, stdout = execute("ps:scale web+2")
109
+ stderr.should == ""
110
+ stdout.should == <<-STDOUT
111
+ Scaling web processes... done, now running 3
112
+ STDOUT
113
+ end
114
+
115
+ end
116
+
117
+ describe "ps:stop" do
118
+
119
+ it "restarts one process" do
120
+ stderr, stdout = execute("ps:restart ps.1")
121
+ stderr.should == ""
122
+ stdout.should == <<-STDOUT
123
+ Restarting ps.1 process... done
124
+ STDOUT
125
+ end
126
+
127
+ it "restarts a type of process" do
128
+ stderr, stdout = execute("ps:restart ps")
129
+ stderr.should == ""
130
+ stdout.should == <<-STDOUT
131
+ Restarting ps processes... done
132
+ STDOUT
133
+ end
134
+
135
+ end
136
+
137
+ end
138
+
139
+ context("non-cedar") do
140
+
141
+ before(:each) do
142
+ api.post_app("name" => "example")
143
+ end
144
+
145
+ after(:each) do
146
+ api.delete_app("example")
147
+ end
148
+
149
+ describe "ps:dynos" do
150
+
151
+ it "displays the current number of dynos" do
152
+ stderr, stdout = execute("ps:dynos")
153
+ stderr.should == ""
154
+ stdout.should == <<-STDOUT
155
+ ~ `azuki ps:dynos QTY` has been deprecated and replaced with `azuki ps:scale dynos=QTY`
156
+ example is running 0 dynos
157
+ STDOUT
158
+ end
159
+
160
+ it "sets the number of dynos" do
161
+ stderr, stdout = execute("ps:dynos 5")
162
+ stderr.should == ""
163
+ stdout.should == <<-STDOUT
164
+ ~ `azuki ps:dynos QTY` has been deprecated and replaced with `azuki ps:scale dynos=QTY`
165
+ Scaling dynos... done, now running 5
166
+ STDOUT
167
+ end
168
+
169
+ end
170
+
171
+ describe "ps:workers" do
172
+
173
+ it "displays the current number of workers" do
174
+ stderr, stdout = execute("ps:workers")
175
+ stderr.should == ""
176
+ stdout.should == <<-STDOUT
177
+ ~ `azuki ps:workers QTY` has been deprecated and replaced with `azuki ps:scale workers=QTY`
178
+ example is running 0 workers
179
+ STDOUT
180
+ end
181
+
182
+ it "sets the number of workers" do
183
+ stderr, stdout = execute("ps:workers 5")
184
+ stderr.should == ""
185
+ stdout.should == <<-STDOUT
186
+ ~ `azuki ps:workers QTY` has been deprecated and replaced with `azuki ps:scale workers=QTY`
187
+ Scaling workers... done, now running 5
188
+ STDOUT
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+
195
+ end