azuki 0.0.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 (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