stackfu 0.1.0

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 (119) hide show
  1. data/CHANGELOG +24 -0
  2. data/Manifest +118 -0
  3. data/README +0 -0
  4. data/README.md +218 -0
  5. data/Rakefile +73 -0
  6. data/bin/stackfu +10 -0
  7. data/lib/stackfu/api_hooks.rb +17 -0
  8. data/lib/stackfu/app.rb +69 -0
  9. data/lib/stackfu/commands/command.rb +127 -0
  10. data/lib/stackfu/commands/config_command.rb +43 -0
  11. data/lib/stackfu/commands/deploy_command.rb +144 -0
  12. data/lib/stackfu/commands/dump_command.rb +101 -0
  13. data/lib/stackfu/commands/generate_command.rb +107 -0
  14. data/lib/stackfu/commands/help_command.rb +28 -0
  15. data/lib/stackfu/commands/list_command.rb +26 -0
  16. data/lib/stackfu/commands/publish_command.rb +108 -0
  17. data/lib/stackfu/commands/server_command.rb +124 -0
  18. data/lib/stackfu/helpers/providers_credentials.rb +82 -0
  19. data/lib/stackfu/helpers/rendering.rb +201 -0
  20. data/lib/stackfu/operating_systems.rb +30 -0
  21. data/lib/stackfu.rb +88 -0
  22. data/stackfu-installer/config/01-controls.yml +17 -0
  23. data/stackfu-installer/config/02-requirements.yml +3 -0
  24. data/stackfu-installer/config/03-scripts.yml +16 -0
  25. data/stackfu-installer/config/04-validations.yml +3 -0
  26. data/stackfu-installer/script/dotfiles_installation.sh.erb +22 -0
  27. data/stackfu-installer/script/github_credentials_setup.sh.erb +31 -0
  28. data/stackfu-installer/script/nginx_and_passenger.sh.erb +83 -0
  29. data/stackfu-installer/script/redis_installation.sh.erb +33 -0
  30. data/stackfu-installer/script/resque_installation.sh.erb +7 -0
  31. data/stackfu-installer/script/ruby_environment.sh.erb +20 -0
  32. data/stackfu-installer/script/stackfu.sh.erb +114 -0
  33. data/stackfu-installer/stack.yml +5 -0
  34. data/stackfu.gemspec +60 -0
  35. data/templates/01-controls.yml.erb +31 -0
  36. data/templates/02-requirements.yml.erb +26 -0
  37. data/templates/03-scripts.yml.erb +34 -0
  38. data/templates/04-validations.yml.erb +17 -0
  39. data/templates/script.sh.erb +7 -0
  40. data/templates/stack.yml.erb +17 -0
  41. data/test/fixtures/add_server_error +7 -0
  42. data/test/fixtures/deployment_add +7 -0
  43. data/test/fixtures/deployment_add_error +8 -0
  44. data/test/fixtures/deployments +7 -0
  45. data/test/fixtures/logs +7 -0
  46. data/test/fixtures/logs_partial +7 -0
  47. data/test/fixtures/plugin_add +6 -0
  48. data/test/fixtures/plugin_add_error +8 -0
  49. data/test/fixtures/plugin_deployment_add +7 -0
  50. data/test/fixtures/plugin_not_found +7 -0
  51. data/test/fixtures/plugin_unauthorized +8 -0
  52. data/test/fixtures/plugins +7 -0
  53. data/test/fixtures/plugins_by_name +7 -0
  54. data/test/fixtures/plugins_by_name_other +7 -0
  55. data/test/fixtures/plugins_empty +7 -0
  56. data/test/fixtures/plugins_multiple +7 -0
  57. data/test/fixtures/providers +7 -0
  58. data/test/fixtures/providers_servers +7 -0
  59. data/test/fixtures/server_add +6 -0
  60. data/test/fixtures/server_add_dupe +7 -0
  61. data/test/fixtures/server_add_error +7 -0
  62. data/test/fixtures/server_delete +7 -0
  63. data/test/fixtures/server_delete_error +7 -0
  64. data/test/fixtures/servers +7 -0
  65. data/test/fixtures/servers_by_name +7 -0
  66. data/test/fixtures/servers_empty +8 -0
  67. data/test/fixtures/servers_not_found +26 -0
  68. data/test/fixtures/servers_unauthorized +8 -0
  69. data/test/fixtures/servers_webbynode +7 -0
  70. data/test/fixtures/stack/stackfu-installer/config/01-controls.yml +22 -0
  71. data/test/fixtures/stack/stackfu-installer/config/02-requirements.yml +1 -0
  72. data/test/fixtures/stack/stackfu-installer/config/03-scripts.yml +23 -0
  73. data/test/fixtures/stack/stackfu-installer/config/04-validations.yml +1 -0
  74. data/test/fixtures/stack/stackfu-installer/script/dotfiles_installation.sh.erb +22 -0
  75. data/test/fixtures/stack/stackfu-installer/script/github_credentials_setup.sh.erb +31 -0
  76. data/test/fixtures/stack/stackfu-installer/script/nginx_and_passenger.sh.erb +83 -0
  77. data/test/fixtures/stack/stackfu-installer/script/redis_installation.sh.erb +33 -0
  78. data/test/fixtures/stack/stackfu-installer/script/resque_installation.sh.erb +7 -0
  79. data/test/fixtures/stack/stackfu-installer/script/ruby_environment.sh.erb +20 -0
  80. data/test/fixtures/stack/stackfu-installer/script/stackfu.sh.erb +76 -0
  81. data/test/fixtures/stack/stackfu-installer/stack.yml +5 -0
  82. data/test/fixtures/stack_add +6 -0
  83. data/test/fixtures/stack_add_error +8 -0
  84. data/test/fixtures/stack_add_error_dupe +8 -0
  85. data/test/fixtures/stack_adds_by_name +7 -0
  86. data/test/fixtures/stack_delete_not_found +7 -0
  87. data/test/fixtures/stacks +7 -0
  88. data/test/fixtures/stacks_by_name +7 -0
  89. data/test/fixtures/stacks_by_name_other +7 -0
  90. data/test/fixtures/stacks_empty +7 -0
  91. data/test/fixtures/stacks_multiple +7 -0
  92. data/test/fixtures/stacks_not_found +7 -0
  93. data/test/fixtures/stacks_realworld +7 -0
  94. data/test/fixtures/stacks_stackfu-installer +7 -0
  95. data/test/fixtures/stacks_unauthorized +8 -0
  96. data/test/fixtures/stacks_with_controls +0 -0
  97. data/test/fixtures/users +7 -0
  98. data/test/fixtures/users_no_credentials +7 -0
  99. data/test/fixtures/users_update +6 -0
  100. data/test/stack.yml +26 -0
  101. data/test/support/custom_matchers.rb +69 -0
  102. data/test/support/fixtures.rb +98 -0
  103. data/test/support/io_stub.rb +10 -0
  104. data/test/support/web_fixtures.rb +91 -0
  105. data/test/test_helper.rb +186 -0
  106. data/test/unit/commands/test_command.rb +112 -0
  107. data/test/unit/commands/test_config_command.rb +92 -0
  108. data/test/unit/commands/test_deploy_command.rb +303 -0
  109. data/test/unit/commands/test_dump_command.rb +155 -0
  110. data/test/unit/commands/test_generate_command.rb +112 -0
  111. data/test/unit/commands/test_help_command.rb +33 -0
  112. data/test/unit/commands/test_list_command.rb +63 -0
  113. data/test/unit/commands/test_publish_command.rb +265 -0
  114. data/test/unit/commands/test_server_command.rb +259 -0
  115. data/test/unit/helpers/test_rendering.rb +141 -0
  116. data/test/unit/test_array.rb +26 -0
  117. data/test/unit/test_provider.rb +14 -0
  118. data/test/unit/test_stackfu.rb +27 -0
  119. metadata +311 -0
@@ -0,0 +1,265 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper.rb'
2
+
3
+ class TestPublishCommand < Test::Unit::TestCase
4
+
5
+ %w(plugin stack).each do |what|
6
+ define_method("setup_#{what}") do |*options|
7
+ options = options.pop || {}
8
+ PublishCommand.any_instance.expects("#{what}?").returns(true)
9
+ PublishCommand.any_instance.expects("#{['stack', 'plugin'] - [what]}?").returns(false)
10
+
11
+ PublishCommand.any_instance.expects(:read).with("#{what}.yml").returns(<<-EOS)
12
+ ---
13
+ type: stack
14
+ name: #{options[:"#{what}_name"] || "my_#{what}"}
15
+ description: "This will deploy my #{what}"
16
+ tags: [mine, #{what}, is, nice]
17
+ EOS
18
+ PublishCommand.any_instance.expects(:read).with("config/01-controls.yml").returns(<<-EOS)
19
+ controls:
20
+ - name: nome
21
+ label: Nome
22
+ type: Textbox
23
+ - name: idade
24
+ label: Idade
25
+ type: Numericbox
26
+ EOS
27
+ PublishCommand.any_instance.expects(:read).with("config/02-requirements.yml").returns(<<-EOS)
28
+ requirements:
29
+
30
+ - type: directory
31
+ data: "/var"
32
+ error: "You need /var folder before installing"
33
+ EOS
34
+ PublishCommand.any_instance.expects(:read).with("config/03-scripts.yml").returns(options[:scripts] || <<-EOS)
35
+ scripts:
36
+
37
+ - description: Echoer
38
+ file: echoer
39
+ EOS
40
+ PublishCommand.any_instance.expects(:read).with("config/04-validations.yml").returns(<<-EOS)
41
+ validations:
42
+ - type: directory
43
+ data: "/etc/apache2"
44
+ error: Apache was not installed properly
45
+ EOS
46
+
47
+ unless options[:scripts]
48
+ PublishCommand.any_instance.expects(:read).with("script/echoer.sh.erb").returns(<<-EOS)
49
+ #
50
+ # echoe.sh
51
+ # Echoes a variable
52
+ #
53
+
54
+ echo "<%= nome %> is <%= age %> years old"
55
+ EOS
56
+ end
57
+ end
58
+ end
59
+
60
+ should "return true for plugin? if file plugin.yml exists" do
61
+ File.expects(:exists?).with("plugin.yml").returns(true)
62
+ PublishCommand.new.plugin?.should be_true
63
+ end
64
+
65
+ should "return true for stack? if file plugin.yml exists" do
66
+ File.expects(:exists?).with("stack.yml").returns(true)
67
+ PublishCommand.new.stack?.should be_true
68
+ end
69
+
70
+ %w(stack plugin).each do |what|
71
+ context "Publish command for a #{what}" do
72
+ should "check if #{what} exists before publishing" do
73
+ send "setup_#{what}"
74
+ send "with_#{what}s", "by_name", "#{what}%5Bname%5D=my_#{what}"
75
+ send "with_#{what}_delete", "4b08748de1054e1477000006"
76
+ send "with_#{what}_add"
77
+
78
+ agree_with("You already have a #{what} named my_#{what}. Do you want to update it?")
79
+
80
+ command "pub"
81
+ stdout.should =~ /Publishing #{what} my_#{what}/
82
+ stdout.should =~ /Success/
83
+ end
84
+
85
+ should "check if #{what} exists but not ask the user for confirmation if --update is provided" do
86
+ send "setup_#{what}"
87
+ send "with_#{what}s", "by_name", "#{what}%5Bname%5D=my_#{what}"
88
+ send "with_#{what}_delete", "4b08748de1054e1477000006"
89
+ send "with_#{what}_add"
90
+
91
+ command "pub --update"
92
+ stdout.should =~ /Publishing #{what} my_#{what}/
93
+ stdout.should =~ /Success/
94
+ end
95
+
96
+ should "tell the user when there's a problem deleting the #{what}" do
97
+ send "setup_#{what}"
98
+ send "with_#{what}s", "by_name", "#{what}%5Bname%5D=my_#{what}"
99
+ send "with_#{what}_delete", "4b08748de1054e1477000006", "server_delete_error"
100
+ send "with_#{what}_add"
101
+
102
+ command "pub --update"
103
+ stdout.should =~ /There was a problem updating your #{what}/
104
+ stdout.should_not =~ /Publishing #{what} my_#{what}/
105
+ end
106
+
107
+ should "be OK when #{what} doesn't exist" do
108
+ send "setup_#{what}"
109
+ send "with_#{what}s", "empty", "#{what}%5Bname%5D=my_#{what}"
110
+ send "with_#{what}_add"
111
+
112
+ command "pub"
113
+ stdout.should =~ /Publishing #{what} my_#{what}/
114
+ stdout.should =~ /Success/
115
+ end
116
+
117
+ should "abort if user responded false to check when #{what} exists before publishing" do
118
+ send "setup_#{what}"
119
+ send "with_#{what}s", "by_name", "#{what}%5Bname%5D=my_#{what}"
120
+ send "with_#{what}_add"
121
+
122
+ disagree_of("You already have a #{what} named my_#{what}. Do you want to update it?")
123
+
124
+ command "pub"
125
+ stdout.should =~ /Abort./
126
+ end
127
+
128
+ should "show the correct #{what} name" do
129
+ send "setup_#{what}", "#{what}_name".to_sym => "bli#{what}"
130
+ send "with_#{what}s", "by_name_other", "#{what}%5Bname%5D=bli#{what}"
131
+ send "with_#{what}_add"
132
+
133
+ disagree_of("You already have a #{what} named bli#{what}. Do you want to update it?")
134
+
135
+ command "pub"
136
+ stdout.should =~ /Abort./
137
+ end
138
+
139
+ should "be aliased to pub" do
140
+ send "setup_#{what}"
141
+ send "with_#{what}s", "empty", "#{what}%5Bname%5D=my_#{what}"
142
+ send "with_#{what}_add"
143
+ command "pub"
144
+ stdout.should =~ /Publishing #{what} my_#{what}/
145
+ stdout.should =~ /Success/
146
+ end
147
+
148
+ should "show an error when a #{what} has no scripts" do
149
+ send "setup_#{what}", :scripts => ""
150
+ command "pub"
151
+ stdout.should =~ /To publish a #{what} you have to define at least one script./
152
+ end
153
+
154
+ should "show an error when a script is not found" do
155
+ PublishCommand.any_instance.expects(:read).with("script/sample.sh.erb").raises(Errno::ENOENT)
156
+ send "setup_#{what}", :scripts => "scripts:\n- file: sample\n description: A script\n"
157
+ command "pub"
158
+ stdout.should =~ /The template file for the script 'A script' was not found./
159
+ end
160
+
161
+ should "show an error if there's no stack.yml and no plugin.yml on the current folder" do
162
+ PublishCommand.any_instance.expects(:stack?).returns(false)
163
+ PublishCommand.any_instance.expects(:plugin?).returns(false)
164
+
165
+ command "publish"
166
+ stdout.should =~ /Couldn't find an item to publish on current folder./
167
+ stdout.should =~ /Make sure you have a file named 'stack.yml'/
168
+ end
169
+
170
+ should "read #{what}.yml file when present" do
171
+ send "setup_#{what}"
172
+ send "with_#{what}s", "empty", "#{what}%5Bname%5D=my_#{what}"
173
+ send "with_#{what}_add"
174
+
175
+ PublishCommand.any_instance.expects(:publish).with { |stack|
176
+ stack.name.should == "my_#{what}"
177
+ stack.description.should == "This will deploy my #{what}"
178
+
179
+ stack.requirements.size.should == 1
180
+ stack.requirements.first.attributes['type'].should == "directory"
181
+ stack.requirements.first.data.should == "/var"
182
+
183
+ stack.controls.size.should == 2
184
+ stack.controls.first.name.should == "nome"
185
+ stack.controls.first.label.should == "Nome"
186
+ stack.controls.first._type.should == "Textbox"
187
+ stack.controls.last._type.should == "Numericbox"
188
+
189
+ stack.validations.size.should == 1
190
+ stack.validations.first.attributes['type'].should == "directory"
191
+ stack.validations.first.data.should == "/etc/apache2"
192
+
193
+ stack.executions.first.script.should =~ /Echoes a variable/
194
+ true
195
+ }.returns(true)
196
+
197
+ command "publish"
198
+ stdout.should =~ /Publishing #{what} my_#{what}/
199
+ stdout.should =~ /Success/
200
+ end
201
+
202
+ should "report server errors" do
203
+ send "setup_#{what}"
204
+ send "with_#{what}s", "empty", "#{what}%5Bname%5D=my_#{what}"
205
+ send "with_#{what}_add", "error"
206
+
207
+ command "publish"
208
+ stdout.should =~ /Publishing #{what} my_#{what}/
209
+ stdout.should =~ /Operating system can't be empty/
210
+ end
211
+ end
212
+ end
213
+ # private
214
+
215
+ # def send "setup_#{what}"(options={})
216
+ # PublishCommand.any_instance.expects(:read).with("stack.yml").returns(<<-EOS)
217
+ # ---
218
+ # type: stack
219
+ # name: #{options[:stack_name] || "my_stack"}
220
+ # description: "This will deploy my stack"
221
+ # tags: [mine, stack, is, nice]
222
+ # EOS
223
+ # PublishCommand.any_instance.expects(:read).with("config/01-controls.yml").returns(<<-EOS)
224
+ # controls:
225
+ # - name: nome
226
+ # label: Nome
227
+ # type: Textbox
228
+ # - name: idade
229
+ # label: Idade
230
+ # type: Numericbox
231
+ # EOS
232
+ # PublishCommand.any_instance.expects(:read).with("config/02-requirements.yml").returns(<<-EOS)
233
+ # requirements:
234
+ #
235
+ # - type: directory
236
+ # data: "/var"
237
+ # error: "You need /var folder before installing"
238
+ # EOS
239
+ # PublishCommand.any_instance.expects(:read).with("config/03-scripts.yml").returns(options[:scripts] || <<-EOS)
240
+ # scripts:
241
+ #
242
+ # - description: Echoer
243
+ # file: echoer
244
+ # EOS
245
+ # PublishCommand.any_instance.expects(:read).with("config/04-validations.yml").returns(<<-EOS)
246
+ # validations:
247
+ # - type: directory
248
+ # data: "/etc/apache2"
249
+ # error: Apache was not installed properly
250
+ # EOS
251
+ #
252
+ # unless options[:scripts]
253
+ # PublishCommand.any_instance.expects(:read).with("script/echoer.sh.erb").returns(<<-EOS)
254
+ # #
255
+ # # echoe.sh
256
+ # # Echoes a variable
257
+ # #
258
+ #
259
+ # echo "<%= nome %> is <%= age %> years old"
260
+ # EOS
261
+ # end
262
+ # end
263
+
264
+
265
+ end
@@ -0,0 +1,259 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper.rb'
2
+
3
+ class TestServerCommand < Test::Unit::TestCase
4
+ should "map 'servers' to ServerCommand" do
5
+ Command.create("servers").class.should == ServerCommand
6
+ end
7
+
8
+ should "map 'server' to ServerCommand" do
9
+ Command.create("server").class.should == ServerCommand
10
+ end
11
+
12
+ context "list servers with invalid user" do
13
+ should "return an user friendly error" do
14
+ with_server_list("unauthorized")
15
+ command "server list"
16
+ stdout.should =~ /Access denied for user 'flipper'/
17
+ end
18
+ end
19
+
20
+ context "list servers with 404" do
21
+ should "return an user friendly error" do
22
+ with_server_list("not_found")
23
+ command "server list"
24
+ stdout.should =~ /There was an internal error contacting StackFu backend./
25
+ end
26
+ end
27
+
28
+ should "indicate user have no servers" do
29
+ with_server_list "empty"
30
+ command "server list"
31
+ stdout.should =~ /You have no servers under your account. Try adding some with 'server add' command.\n/
32
+ end
33
+
34
+ context "add command" do
35
+ should "require two parameters" do
36
+ command "server add Slicehost"
37
+ stdout.should =~ /requires 2 parameters/
38
+ end
39
+ end
40
+
41
+ context "adding a server" do
42
+ should "fail when adding to add the same server twice" do
43
+ with_users
44
+ with_server_add("dupe")
45
+
46
+ command "server add Slicehost slicey"
47
+ stdout.should =~ /already exists in your account./
48
+ end
49
+
50
+ should "ask for credentials before the walkthrough if user have no credentials" do
51
+ with_users "no_credentials"
52
+ with_users_add
53
+ with_providers
54
+ with_provider("slicehost", "servers")
55
+ with_server_add
56
+
57
+ when_asked_to_choose "\nSelect the provider:",
58
+ :with_options => ["Webbynode", "Slicehost", "Linode"],
59
+ :answer => 1
60
+
61
+ when_asked "", :answer => "abc123"
62
+
63
+ when_asked_to_choose "\nSelect the server:",
64
+ :with_options => ["slicey", "peeps"],
65
+ :answer => 1
66
+
67
+ command "server add"
68
+
69
+ stdout.should =~ /Slicehost credentials saved/
70
+ stdout.should =~ /Server peeps added successfully/
71
+ end
72
+
73
+ should "fail when adding to add the same server twice and using the walkthrough" do
74
+ with_users
75
+ with_providers
76
+ with_provider("slicehost", "servers")
77
+ with_server_add("dupe")
78
+
79
+ when_asked_to_choose "\nSelect the provider:",
80
+ :with_options => ["Webbynode", "Slicehost", "Linode"],
81
+ :answer => 1
82
+
83
+ when_asked_to_choose "\nSelect the server:",
84
+ :with_options => ["slicey", "peeps"],
85
+ :answer => 1
86
+
87
+ command "server add"
88
+
89
+ stdout.should =~ /already exists in your account./
90
+ end
91
+
92
+ should "guide the user to add a server when no params are given" do
93
+ with_users
94
+ with_providers
95
+ with_provider("slicehost", "servers")
96
+ with_server_add
97
+
98
+ when_asked_to_choose "\nSelect the provider:",
99
+ :with_options => ["Webbynode", "Slicehost", "Linode"],
100
+ :answer => 1
101
+
102
+ when_asked_to_choose "\nSelect the server:",
103
+ :with_options => ["slicey", "peeps"],
104
+ :answer => 1
105
+
106
+ command "server add"
107
+ end
108
+ end
109
+
110
+ context "adding a webbynode server" do
111
+ should "abort when user enters 'abort' into the API login field" do
112
+ with_users "no_credentials"
113
+
114
+ when_asked "Webbynode Login:", :answer => 'abort'
115
+ command "server add webbynode sandbox"
116
+
117
+ stdout.should =~ /Aborted adding server./
118
+ stdout.should =~ /Enter your Webbynode API credentials/
119
+ end
120
+
121
+ should "abort when user enters 'abort' into the API token field" do
122
+ with_users "no_credentials"
123
+
124
+ when_asked "Webbynode Login:", :answer => 'fcoury@me.com'
125
+ when_asked "Webbynode Token:", :answer => 'abort'
126
+
127
+ command "server add webbynode sandbox"
128
+
129
+ stdout.should =~ /Aborted adding server./
130
+ stdout.should =~ /Enter your Webbynode API credentials/
131
+ end
132
+
133
+ should "show the help message when user enters 'help' into the API login field" do
134
+ with_users "no_credentials"
135
+
136
+ when_asked "Webbynode Login:", :answer => 'help'
137
+ when_asked "Webbynode Login:", :answer => 'abort'
138
+ command "server add webbynode sandbox"
139
+
140
+ stdout.should =~ /== Webbynode StackFu integration ==/
141
+ end
142
+
143
+ should "ask for credentials when none were given before" do
144
+ with_users "no_credentials"
145
+ with_users_add
146
+ with_server_add
147
+
148
+ when_asked "Webbynode Login:", :answer => 'fcoury@me.com'
149
+ when_asked "Webbynode Token:", :answer => 'abc123456'
150
+
151
+ command "server add webbynode sandbox"
152
+ stdout.should =~ /Webbynode credentials saved./
153
+ stdout.should =~ /Server sandbox added successfully/
154
+ end
155
+
156
+ should "add the server if proper credentials given" do
157
+ with_users
158
+ with_users_add
159
+ with_server_add
160
+
161
+ command "server add webbynode sandbox"
162
+ stdout.should =~ /Server sandbox added successfully/
163
+ end
164
+
165
+ should "delete the server if proper credentials given and server exists" do
166
+ with_users
167
+ with_server_list("webbynode")
168
+ with_server_delete
169
+
170
+ command "server delete sandbox"
171
+ stdout.should =~ /Server sandbox deleted successfully/
172
+ end
173
+
174
+ should "show the webbynode server when listing servers" do
175
+ with_users
176
+ with_server_list("webbynode")
177
+
178
+ command "server"
179
+ stdout.should =~ /Name/
180
+ stdout.should =~ /Provider/
181
+ stdout.should =~ /IP/
182
+ stdout.should =~ /Status/
183
+
184
+ stdout.should =~ /sandbox/
185
+ stdout.should =~ /Webbynode/
186
+ stdout.should =~ /208\.88\.125\.207/
187
+ stdout.should =~ /running/
188
+ end
189
+ end
190
+
191
+ context "adding a slicehost server" do
192
+ should "abort when user enters 'abort' into the API password field" do
193
+ with_users "no_credentials"
194
+
195
+ when_asked "", :answer => 'abort'
196
+ command "server add slicehost slicey"
197
+
198
+ stdout.should =~ /Aborted adding server./
199
+ stdout.should =~ /Enter your Slicehost API password/
200
+ end
201
+
202
+ should "show the help message when user enters 'help' into the API password field" do
203
+ with_users "no_credentials"
204
+
205
+ when_asked "", :answer => 'help'
206
+ when_asked "", :answer => 'abort'
207
+ command "server add slicehost slicey"
208
+
209
+ stdout.should =~ /== Slicehost StackFu integration ==/
210
+ end
211
+
212
+ should "ask for credentials when none were given before" do
213
+ with_users "no_credentials"
214
+ with_users_add
215
+ with_server_add
216
+
217
+ when_asked "", :answer => "abc123"
218
+
219
+ command "server add slicehost slicey"
220
+ stdout.should =~ /Server slicey added successfully/
221
+ end
222
+
223
+ should "add the server if proper credentials given" do
224
+ with_users
225
+ with_users_add
226
+ with_server_add
227
+
228
+ command "server add slicehost slicey"
229
+ stdout.should =~ /Server slicey added successfully/
230
+ end
231
+
232
+ should "delete the server if proper credentials given and server exists" do
233
+ with_users
234
+ with_server_list
235
+ with_server_delete
236
+
237
+ command "server delete slicey"
238
+ stdout.should =~ /Server slicey deleted successfully/
239
+ end
240
+
241
+ should "show a selection when same server hostname repeats in more than one provider"
242
+
243
+ should "show the slicehost server when listing servers" do
244
+ with_users
245
+ with_server_list
246
+
247
+ command "server"
248
+ stdout.should =~ /Name/
249
+ stdout.should =~ /Provider/
250
+ stdout.should =~ /IP/
251
+ stdout.should =~ /Status/
252
+
253
+ stdout.should =~ /slicey/
254
+ stdout.should =~ /Slicehost/
255
+ stdout.should =~ /174\.143\.145\.37/
256
+ stdout.should =~ /running/
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,141 @@
1
+ require File.dirname(__FILE__) + '/../../test_helper.rb'
2
+
3
+ class TestRendering < Test::Unit::TestCase
4
+ include StackFu::Rendering
5
+
6
+ class Pizza
7
+ attr_accessor :flavor, :size, :price
8
+
9
+ def initialize(flavor, size, price)
10
+ @flavor = flavor
11
+ @size = size
12
+ @price = price
13
+ end
14
+ end
15
+
16
+ context "lists" do
17
+ should "render a list with the object collection and all properties by default" do
18
+ pizzas = [
19
+ Pizza.new("Mozzarella", "Large", 14.99),
20
+ Pizza.new("Margheritta", "Large", 15.99),
21
+ Pizza.new("Pequenita", nil, 5.99),
22
+ Pizza.new("Pepperoni", "Large", 17.99)
23
+ ]
24
+
25
+ table = table(:class => Pizza, :collection => pizzas, :display => [:flavor, :size, :price], :ansi => false)
26
+ table.should =~ /^Listing 4 pizzas:/
27
+ table.should =~ / Flavor Size Price/
28
+ table.should =~ / ------------ ------ -----/
29
+ table.should =~ / Mozzarella Large 14.99/
30
+ table.should =~ / Margheritta Large 15.99/
31
+ table.should =~ / Pequenita 5.99/
32
+ table.should =~ / Pepperoni Large 17.99/
33
+ end
34
+
35
+ should "accept a block and render based on the block" do
36
+ pizzas = [
37
+ Pizza.new("Mozzarella", "Large", 14.99),
38
+ Pizza.new("Margheritta", "Large", 15.99),
39
+ Pizza.new("Pequenita", nil, 5.99),
40
+ ]
41
+
42
+ table = table(:class => Pizza, :collection => pizzas, :display => [:flavor, :size, :price], :ansi => false) do |item|
43
+ ["Mah #{item.flavor}", "#{item.size.try(:downcase)}", item.price + 2]
44
+ end
45
+ table.should =~ /^Listing 3 pizzas:/
46
+ table.should =~ / Flavor Size Price/
47
+ table.should =~ / ---------------- ------ -----/
48
+ table.should =~ / Mah Mozzarella large 16.99/
49
+ table.should =~ / Mah Margheritta large 17.99/
50
+ table.should =~ / Mah Pequenita 7.99/
51
+ end
52
+
53
+ should "pluralize the description before the table" do
54
+ class Dash < Pizza
55
+ end
56
+
57
+ pizzas = [
58
+ Dash.new("Mozzarella", "Large", 14.99)
59
+ ]
60
+
61
+ table = table(:class => Dash, :collection => pizzas, :display => [:flavor, :size, :price], :ansi => false) do |item|
62
+ ["Mah #{item.flavor}", "#{item.size.try(:downcase)}", item.price + 2]
63
+ end
64
+ table.should =~ /^Listing 1 dash:/
65
+ table.should =~ / Flavor Size Price/
66
+ table.should =~ / --------------- ------ -----/
67
+ table.should =~ / Mah Mozzarella large 16.99/
68
+
69
+ pizzas << Dash.new("Minina", "Large", 14.99)
70
+
71
+ table = table(:class => Dash, :collection => pizzas, :display => [:flavor, :size, :price], :ansi => false) do |item|
72
+ ["Mah #{item.flavor}", "#{item.size.try(:downcase)}", item.price + 2]
73
+ end
74
+ table.should =~ /^Listing 2 dashes:/
75
+ table.should =~ / Flavor Size Price/
76
+ table.should =~ / --------------- ------ -----/
77
+ table.should =~ / Mah Mozzarella large 16.99/
78
+ end
79
+
80
+ should "render an empty message if no items" do
81
+ pizzas = []
82
+ table = table(:class => Pizza, :collection => pizzas, :display => [:flavor, :size, :price], :ansi => false)
83
+ table.should =~ /No pizzas./
84
+ end
85
+
86
+ should "render a custom empty message if no items and custom message passed" do
87
+ pizzas = []
88
+ table = table(:class => Pizza, :collection => pizzas,
89
+ :display => [:flavor, :size, :price], :empty => "Sorry dude, no pizzas!")
90
+ table.should =~ /Sorry dude, no pizzas!/
91
+ end
92
+
93
+ should "two objects with same duck type" do
94
+ class Animal
95
+ attr_accessor :name
96
+ def initialize(name)
97
+ @name = name
98
+ end
99
+ end
100
+
101
+ class Dog < Animal
102
+ def legs; 4; end
103
+ end
104
+
105
+ class Spider < Animal
106
+ def legs; 8; end
107
+ end
108
+
109
+ class Fly < Animal
110
+ def legs; 6; end
111
+ end
112
+
113
+ animals = [Dog.new("Jimmy"), Dog.new("Buddy"), Fly.new("Buggah"), Spider.new("Mommy")]
114
+ table = table(
115
+ :class => [Dog, Fly, Spider],
116
+ :display => [:name, :legs],
117
+ :collection => animals, :ansi => false
118
+ )
119
+
120
+ table.should =~ /^Listing 2 dogs, 1 fly and 1 spider/
121
+ table.should =~ / Name Legs /
122
+ table.should =~ / ------- -----/
123
+ table.should =~ / Jimmy 4/
124
+ table.should =~ / Buddy 4/
125
+ table.should =~ / Buggah 6/
126
+ table.should =~ / Mommy 8/
127
+ end
128
+
129
+ should "render a custom headline" do
130
+ pizzas = [Pizza.new("Mozzarella", "Large", 14.99)]
131
+ table = table(
132
+ :class => Pizza,
133
+ :collection => pizzas,
134
+ :display => [:flavor, :size, :price],
135
+ :header => "We have some pizzas for you")
136
+
137
+ table.should =~ /^We have some pizzas for you/
138
+ table.should_not =~ /^Listing 1 pizza/
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ class TestArray < Test::Unit::TestCase
4
+ should "delete correctly with delete_first" do
5
+ arr = ["a","v","a"]
6
+ arr2 = [{ "felipe" => "yes" }, { "others" => "no" }]
7
+
8
+ arr.delete_first("z").should == nil
9
+ arr.delete_first("a").should == "a"
10
+ arr.should == ["v", "a"]
11
+
12
+ arr.delete_first {|i| i == "a"}.should == "a"
13
+ arr.should == ["v"]
14
+
15
+ arr2.delete_first { |i| i.keys.first == "felipe" }.values.first.should == "yes"
16
+ end
17
+
18
+ should "transform into a struct using to_struct" do
19
+ structs = [{"name" => "Felipe", "id" => "1"},{:name => "Pablo", :id => 2}].to_structs
20
+
21
+ structs.first.name.should == "Felipe"
22
+ structs.first.id.should == "1"
23
+ structs.last.name.should == "Pablo"
24
+ structs.last.id.should == 2
25
+ end
26
+ end