minestrone 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 (96) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/main.yml +32 -0
  3. data/.gitignore +5 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +35 -0
  7. data/Rakefile +10 -0
  8. data/bin/capify +89 -0
  9. data/bin/min +5 -0
  10. data/docs/lib-codebase-map.md +162 -0
  11. data/docs/lib-dependency-graph.svg +129 -0
  12. data/lib/minestrone/callback.rb +45 -0
  13. data/lib/minestrone/cli/help.rb +131 -0
  14. data/lib/minestrone/cli/help.txt +72 -0
  15. data/lib/minestrone/cli/options.rb +232 -0
  16. data/lib/minestrone/cli.rb +159 -0
  17. data/lib/minestrone/command.rb +177 -0
  18. data/lib/minestrone/configuration/actions/file_transfer.rb +53 -0
  19. data/lib/minestrone/configuration/actions/inspect.rb +46 -0
  20. data/lib/minestrone/configuration/actions/invocation.rb +202 -0
  21. data/lib/minestrone/configuration/alias_task.rb +29 -0
  22. data/lib/minestrone/configuration/callbacks.rb +129 -0
  23. data/lib/minestrone/configuration/connections.rb +66 -0
  24. data/lib/minestrone/configuration/execution.rb +139 -0
  25. data/lib/minestrone/configuration/loading.rb +207 -0
  26. data/lib/minestrone/configuration/log_formatters.rb +75 -0
  27. data/lib/minestrone/configuration/namespaces.rb +225 -0
  28. data/lib/minestrone/configuration/servers.rb +70 -0
  29. data/lib/minestrone/configuration/variables.rb +115 -0
  30. data/lib/minestrone/configuration.rb +69 -0
  31. data/lib/minestrone/errors.rb +17 -0
  32. data/lib/minestrone/ext/string.rb +7 -0
  33. data/lib/minestrone/extensions.rb +56 -0
  34. data/lib/minestrone/logger.rb +171 -0
  35. data/lib/minestrone/processable.rb +50 -0
  36. data/lib/minestrone/recipes/deploy/assets.rb +194 -0
  37. data/lib/minestrone/recipes/deploy/bundler.rb +81 -0
  38. data/lib/minestrone/recipes/deploy/dependencies.rb +44 -0
  39. data/lib/minestrone/recipes/deploy/local_dependency.rb +45 -0
  40. data/lib/minestrone/recipes/deploy/remote_dependency.rb +119 -0
  41. data/lib/minestrone/recipes/deploy/scm/base.rb +204 -0
  42. data/lib/minestrone/recipes/deploy/scm/git.rb +284 -0
  43. data/lib/minestrone/recipes/deploy/scm/none.rb +54 -0
  44. data/lib/minestrone/recipes/deploy/scm.rb +22 -0
  45. data/lib/minestrone/recipes/deploy/strategy/base.rb +87 -0
  46. data/lib/minestrone/recipes/deploy/strategy/copy.rb +353 -0
  47. data/lib/minestrone/recipes/deploy/strategy/remote_cache.rb +80 -0
  48. data/lib/minestrone/recipes/deploy/strategy.rb +22 -0
  49. data/lib/minestrone/recipes/deploy.rb +639 -0
  50. data/lib/minestrone/recipes/standard.rb +23 -0
  51. data/lib/minestrone/recipes/templates/maintenance.rhtml +53 -0
  52. data/lib/minestrone/server_definition.rb +56 -0
  53. data/lib/minestrone/ssh.rb +81 -0
  54. data/lib/minestrone/task_definition.rb +82 -0
  55. data/lib/minestrone/transfer.rb +205 -0
  56. data/lib/minestrone/version.rb +11 -0
  57. data/lib/minestrone.rb +3 -0
  58. data/minestrone.gemspec +32 -0
  59. data/test/cli/execute_test.rb +130 -0
  60. data/test/cli/help_test.rb +178 -0
  61. data/test/cli/options_test.rb +315 -0
  62. data/test/cli/ui_test.rb +26 -0
  63. data/test/cli_test.rb +17 -0
  64. data/test/command_test.rb +305 -0
  65. data/test/configuration/actions/file_transfer_test.rb +61 -0
  66. data/test/configuration/actions/inspect_test.rb +76 -0
  67. data/test/configuration/actions/invocation_test.rb +258 -0
  68. data/test/configuration/alias_task_test.rb +110 -0
  69. data/test/configuration/callbacks_test.rb +201 -0
  70. data/test/configuration/connections_test.rb +192 -0
  71. data/test/configuration/execution_test.rb +176 -0
  72. data/test/configuration/loading_test.rb +149 -0
  73. data/test/configuration/namespace_dsl_test.rb +325 -0
  74. data/test/configuration/servers_test.rb +100 -0
  75. data/test/configuration/variables_test.rb +191 -0
  76. data/test/configuration_test.rb +77 -0
  77. data/test/deploy/local_dependency_test.rb +61 -0
  78. data/test/deploy/remote_dependency_test.rb +146 -0
  79. data/test/deploy/scm/base_test.rb +55 -0
  80. data/test/deploy/scm/git_test.rb +260 -0
  81. data/test/deploy/scm/none_test.rb +26 -0
  82. data/test/deploy/strategy/copy_test.rb +360 -0
  83. data/test/extensions_test.rb +69 -0
  84. data/test/fixtures/cli_integration.rb +5 -0
  85. data/test/fixtures/config.rb +4 -0
  86. data/test/fixtures/custom.rb +3 -0
  87. data/test/logger_formatting_test.rb +149 -0
  88. data/test/logger_test.rb +134 -0
  89. data/test/recipes_test.rb +26 -0
  90. data/test/server_definition_test.rb +121 -0
  91. data/test/ssh_test.rb +99 -0
  92. data/test/task_definition_test.rb +117 -0
  93. data/test/transfer_test.rb +172 -0
  94. data/test/utils.rb +28 -0
  95. data/test/version_test.rb +11 -0
  96. metadata +258 -0
@@ -0,0 +1,149 @@
1
+ require 'utils'
2
+ require 'minestrone/configuration/loading'
3
+
4
+ class ConfigurationLoadingTest < Test::Unit::TestCase
5
+ class MockConfig
6
+ attr_accessor :ping
7
+ attr_reader :original_initialize_called
8
+
9
+ def initialize
10
+ @original_initialize_called = true
11
+ initialize_loading
12
+ end
13
+
14
+ def ping!(value)
15
+ @ping = value
16
+ end
17
+
18
+ include Minestrone::Configuration::Loading
19
+ end
20
+
21
+ def setup
22
+ @config = MockConfig.new
23
+ end
24
+
25
+ def teardown
26
+ MockConfig.instance = nil
27
+ $LOADED_FEATURES.delete_if { |a| a =~ /fixtures\/custom\.rb$/ }
28
+ end
29
+
30
+ def test_initialize_should_init_collections
31
+ assert @config.original_initialize_called
32
+ assert @config.load_paths.include?(".")
33
+ assert @config.load_paths.detect { |v| v =~ /minestrone\/recipes$/ }
34
+ end
35
+
36
+ def test_load_with_options_and_block_should_raise_argument_error
37
+ assert_raises(ArgumentError) do
38
+ @config.load(:string => "foo") { something }
39
+ end
40
+ end
41
+
42
+ def test_load_with_arguments_and_block_should_raise_argument_error
43
+ assert_raises(ArgumentError) do
44
+ @config.load("foo") { something }
45
+ end
46
+ end
47
+
48
+ def test_load_from_string_should_eval_in_config_scope
49
+ @config.load :string => "ping! :here"
50
+ assert_equal :here, @config.ping
51
+ end
52
+
53
+ def test_load_from_file_shoudld_respect_load_path
54
+ File.stubs(:file?).returns(false)
55
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
56
+ File.stubs(:read).with("custom/path/for/file.rb").returns("ping! :here")
57
+
58
+ @config.load_paths << "custom/path/for"
59
+ @config.load :file => "file.rb"
60
+
61
+ assert_equal :here, @config.ping
62
+ end
63
+
64
+ def test_load_from_file_should_respect_load_path_and_appends_rb
65
+ File.stubs(:file?).returns(false)
66
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
67
+ File.stubs(:read).with("custom/path/for/file.rb").returns("ping! :here")
68
+
69
+ @config.load_paths << "custom/path/for"
70
+ @config.load :file => "file"
71
+
72
+ assert_equal :here, @config.ping
73
+ end
74
+
75
+ def test_load_from_file_should_raise_load_error_if_file_cannot_be_found
76
+ File.stubs(:file?).returns(false)
77
+ assert_raises(LoadError) do
78
+ @config.load :file => "file"
79
+ end
80
+ end
81
+
82
+ def test_load_from_proc_should_eval_proc_in_config_scope
83
+ @config.load :proc => Proc.new { ping! :here }
84
+ assert_equal :here, @config.ping
85
+ end
86
+
87
+ def test_load_with_block_should_treat_block_as_proc_parameter
88
+ @config.load { ping! :here }
89
+ assert_equal :here, @config.ping
90
+ end
91
+
92
+ def test_load_with_unrecognized_option_should_raise_argument_error
93
+ assert_raises(ArgumentError) do
94
+ @config.load :url => "http://www.load-this.test"
95
+ end
96
+ end
97
+
98
+ def test_load_with_arguments_should_treat_arguments_as_files
99
+ File.stubs(:file?).returns(false)
100
+ File.stubs(:file?).with("./first.rb").returns(true)
101
+ File.stubs(:file?).with("./second.rb").returns(true)
102
+ File.stubs(:read).with("./first.rb").returns("ping! 'this'")
103
+ File.stubs(:read).with("./second.rb").returns("ping << 'that'")
104
+ assert_nothing_raised { @config.load "first", "second" }
105
+ assert_equal "thisthat", @config.ping
106
+ end
107
+
108
+ def test_require_from_config_should_load_file_in_config_scope
109
+ assert_nothing_raised do
110
+ @config.require "#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom"
111
+ end
112
+ assert_equal :custom, @config.ping
113
+ end
114
+
115
+ def test_require_without_config_should_raise_load_error
116
+ assert_raises(LoadError) do
117
+ require "#{File.dirname(__FILE__)}/../fixtures/custom"
118
+ end
119
+ end
120
+
121
+ def test_require_from_config_should_return_false_when_called_a_second_time_with_same_args
122
+ assert @config.require("#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom")
123
+ assert_equal false, @config.require("#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom")
124
+ end
125
+
126
+ def test_require_in_multiple_instances_should_load_recipes_in_each_instance
127
+ config2 = MockConfig.new
128
+ @config.require "#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom"
129
+ config2.require "#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom"
130
+ assert_equal :custom, @config.ping
131
+ assert_equal :custom, config2.ping
132
+ end
133
+
134
+ def test_file_in_load_path_returns_true_when_file_is_in_load_path
135
+ File.stubs(:file?).returns(false)
136
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
137
+
138
+ @config.load_paths << "custom/path/for"
139
+ assert_equal true, @config.file_in_load_path?("file")
140
+ end
141
+
142
+ def test_file_in_load_path_returns_false_when_file_is_not_in_load_path
143
+ File.stubs(:file?).returns(false)
144
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(false)
145
+
146
+ @config.load_paths << "custom/path/for"
147
+ assert_equal false, @config.file_in_load_path?("file")
148
+ end
149
+ end
@@ -0,0 +1,325 @@
1
+ require "utils"
2
+ require 'minestrone/configuration/namespaces'
3
+
4
+ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
5
+ class MockConfig
6
+ attr_reader :original_initialize_called, :options
7
+
8
+ def initialize
9
+ @original_initialize_called = true
10
+ @options = {}
11
+ initialize_namespaces
12
+ end
13
+
14
+ include Minestrone::Configuration::Namespaces
15
+ end
16
+
17
+ def setup
18
+ @config = MockConfig.new
19
+ end
20
+
21
+ def test_initialize_should_initialize_collections
22
+ assert @config.original_initialize_called
23
+ assert @config.tasks.empty?
24
+ assert @config.namespaces.empty?
25
+ end
26
+
27
+ def test_unqualified_task_should_define_task_at_top_namespace
28
+ assert !@config.tasks.key?(:testing)
29
+ @config.task(:testing) { puts "something" }
30
+ assert @config.tasks.key?(:testing)
31
+ end
32
+
33
+ def test_qualification_should_define_task_within_namespace
34
+ @config.namespace(:testing) do
35
+ task(:nested) { puts "nested" }
36
+ end
37
+
38
+ assert !@config.tasks.key?(:nested)
39
+ assert @config.namespaces.key?(:testing)
40
+ assert @config.namespaces[:testing].tasks.key?(:nested)
41
+ end
42
+
43
+ def test_namespace_within_namespace_should_define_task_within_nested_namespace
44
+ @config.namespace :outer do
45
+ namespace :inner do
46
+ task :nested do
47
+ puts "nested"
48
+ end
49
+ end
50
+ end
51
+
52
+ assert !@config.tasks.key?(:nested)
53
+ assert @config.namespaces.key?(:outer)
54
+ assert @config.namespaces[:outer].namespaces.key?(:inner)
55
+ assert @config.namespaces[:outer].namespaces[:inner].tasks.key?(:nested)
56
+ end
57
+
58
+ def test_pending_desc_should_apply_only_to_immediately_subsequent_task
59
+ @config.desc "A description"
60
+ @config.task(:testing) { puts "foo" }
61
+ @config.task(:another) { puts "bar" }
62
+ assert_equal "A description", @config.tasks[:testing].desc
63
+ assert_nil @config.tasks[:another].desc
64
+ end
65
+
66
+ def test_pending_desc_should_apply_only_to_next_task_in_any_namespace
67
+ @config.desc "A description"
68
+ @config.namespace(:outer) { task(:testing) { puts "foo" } }
69
+ assert_equal "A description", @config.namespaces[:outer].tasks[:testing].desc
70
+ end
71
+
72
+ def test_defining_task_without_block_should_raise_error
73
+ assert_raises(ArgumentError) do
74
+ @config.task(:testing)
75
+ end
76
+ end
77
+
78
+ def test_defining_task_that_shadows_existing_method_should_raise_error
79
+ assert_raises(ArgumentError) do
80
+ @config.task(:sprintf) { puts "foo" }
81
+ end
82
+ end
83
+
84
+ def test_defining_task_that_shadows_existing_namespace_should_raise_error
85
+ @config.namespace(:outer) {}
86
+ assert_raises(ArgumentError) do
87
+ @config.task(:outer) { puts "foo" }
88
+ end
89
+ end
90
+
91
+ def test_defining_namespace_that_shadows_existing_method_should_raise_error
92
+ assert_raises(ArgumentError) do
93
+ @config.namespace(:sprintf) {}
94
+ end
95
+ end
96
+
97
+ def test_defining_namespace_that_shadows_existing_task_should_raise_error
98
+ @config.task(:testing) { puts "foo" }
99
+ assert_raises(ArgumentError) do
100
+ @config.namespace(:testing) {}
101
+ end
102
+ end
103
+
104
+ def test_defining_task_that_shadows_existing_task_should_not_raise_error
105
+ @config.task(:original) { puts "foo" }
106
+ assert_nothing_raised do
107
+ @config.task(:original) { puts "bar" }
108
+ end
109
+ end
110
+
111
+ def test_defining_ask_should_add_task_as_method
112
+ assert !@config.methods.any? { |m| m.to_sym == :original }
113
+ @config.task(:original) { puts "foo" }
114
+ assert @config.methods.any? { |m| m.to_sym == :original }
115
+ end
116
+
117
+ def test_calling_defined_task_should_delegate_to_execute_task
118
+ @config.task(:original) { puts "foo" }
119
+ @config.expects(:execute_task).with(@config.tasks[:original])
120
+ @config.original
121
+ end
122
+
123
+ def test_name_for_top_level_should_be_nil
124
+ assert_nil @config.name
125
+ end
126
+
127
+ def test_parent_for_top_level_should_be_nil
128
+ assert_nil @config.parent
129
+ end
130
+
131
+ def test_fqn_for_top_level_should_be_nil
132
+ assert_nil @config.fully_qualified_name
133
+ end
134
+
135
+ def test_fqn_for_namespace_should_be_the_name_of_the_namespace
136
+ @config.namespace(:outer) {}
137
+ assert_equal "outer", @config.namespaces[:outer].fully_qualified_name
138
+ end
139
+
140
+ def test_parent_for_namespace_should_be_the_top_level
141
+ @config.namespace(:outer) {}
142
+ assert_equal @config, @config.namespaces[:outer].parent
143
+ end
144
+
145
+ def test_fqn_for_nested_namespace_should_be_color_delimited
146
+ @config.namespace(:outer) { namespace(:inner) {} }
147
+ assert_equal "outer:inner", @config.namespaces[:outer].namespaces[:inner].fully_qualified_name
148
+ end
149
+
150
+ def test_parent_for_nested_namespace_should_be_the_nesting_namespace
151
+ @config.namespace(:outer) { namespace(:inner) {} }
152
+ assert_equal @config.namespaces[:outer], @config.namespaces[:outer].namespaces[:inner].parent
153
+ end
154
+
155
+ def test_find_task_should_dereference_nested_tasks
156
+ @config.namespace(:outer) do
157
+ namespace(:inner) { task(:nested) { puts "nested" } }
158
+ end
159
+
160
+ task = @config.find_task("outer:inner:nested")
161
+ assert_not_nil task
162
+ assert_equal "outer:inner:nested", task.fully_qualified_name
163
+ end
164
+
165
+ def test_find_task_should_return_nil_if_no_task_matches
166
+ assert_nil @config.find_task("outer:inner:nested")
167
+ end
168
+
169
+ def test_find_task_should_return_default_if_deferences_to_namespace_and_namespace_has_default
170
+ @config.namespace(:outer) do
171
+ namespace(:inner) { task(:default) { puts "nested" } }
172
+ end
173
+
174
+ task = @config.find_task("outer:inner")
175
+ assert_not_nil task
176
+ assert_equal :default, task.name
177
+ assert_equal "outer:inner", task.namespace.fully_qualified_name
178
+ end
179
+
180
+ def test_find_task_should_return_nil_if_deferences_to_namespace_and_namespace_has_no_default
181
+ @config.namespace(:outer) do
182
+ namespace(:inner) { task(:nested) { puts "nested" } }
183
+ end
184
+
185
+ assert_nil @config.find_task("outer:inner")
186
+ end
187
+
188
+ def test_default_task_should_return_nil_for_top_level
189
+ @config.task(:default) {}
190
+ assert_nil @config.default_task
191
+ end
192
+
193
+ def test_default_task_should_return_nil_for_namespace_without_default
194
+ @config.namespace(:outer) { task(:nested) { puts "nested" } }
195
+ assert_nil @config.namespaces[:outer].default_task
196
+ end
197
+
198
+ def test_default_task_should_return_task_for_namespace_with_default
199
+ @config.namespace(:outer) { task(:default) { puts "nested" } }
200
+ task = @config.namespaces[:outer].default_task
201
+ assert_not_nil task
202
+ assert_equal :default, task.name
203
+ end
204
+
205
+ def test_task_list_should_return_only_tasks_immediately_within_namespace
206
+ @config.task(:first) { puts "here" }
207
+ @config.namespace(:outer) do
208
+ task(:second) { puts "here" }
209
+ namespace(:inner) do
210
+ task(:third) { puts "here" }
211
+ end
212
+ end
213
+
214
+ assert_equal %w(first), @config.task_list.map { |t| t.fully_qualified_name }
215
+ end
216
+
217
+ def test_task_list_with_all_should_return_all_tasks_under_this_namespace_recursively
218
+ @config.task(:first) { puts "here" }
219
+ @config.namespace(:outer) do
220
+ task(:second) { puts "here" }
221
+ namespace(:inner) do
222
+ task(:third) { puts "here" }
223
+ end
224
+ end
225
+
226
+ assert_equal %w(first outer:inner:third outer:second), @config.task_list(:all).map { |t| t.fully_qualified_name }.sort
227
+ end
228
+
229
+ def test_namespace_should_respond_to_its_parents_methods
230
+ @config.namespace(:outer) {}
231
+ ns = @config.namespaces[:outer]
232
+ assert ns.respond_to?(:original_initialize_called)
233
+ end
234
+
235
+ def test_namespace_should_accept_respond_to_with_include_priv_parameter
236
+ @config.namespace(:outer) {}
237
+ ns = @config.namespaces[:outer]
238
+ assert ns.respond_to?(:original_initialize_called, true)
239
+ end
240
+
241
+ def test_namespace_should_delegate_unknown_messages_to_its_parent
242
+ @config.namespace(:outer) {}
243
+ ns = @config.namespaces[:outer]
244
+ assert ns.original_initialize_called
245
+ end
246
+
247
+ def test_namespace_should_not_understand_messages_that_neither_it_nor_its_parent_understands
248
+ @config.namespace(:outer) {}
249
+ ns = @config.namespaces[:outer]
250
+ assert_raises(NoMethodError) { ns.alskdfjlsf }
251
+ end
252
+
253
+ def test_search_task_should_find_tasks_in_current_namespace
254
+ @config.namespace(:outer) do
255
+ namespace(:inner) do
256
+ task(:third) { puts "here" }
257
+ end
258
+ end
259
+
260
+ inner = @config.namespaces[:outer].namespaces[:inner]
261
+ assert_equal inner.tasks[:third], inner.search_task(:third)
262
+ end
263
+
264
+ def test_search_task_should_find_tasks_in_parent_namespace
265
+ @config.task(:first) { puts "here" }
266
+ @config.namespace(:outer) do
267
+ task(:second) { puts "here" }
268
+ namespace(:inner) do
269
+ task(:third) { puts "here" }
270
+ end
271
+ end
272
+
273
+ inner = @config.namespaces[:outer].namespaces[:inner]
274
+ assert_equal @config.tasks[:first], inner.search_task(:first)
275
+ end
276
+
277
+ def test_search_task_should_return_nil_if_no_tasks_are_found
278
+ @config.namespace(:outer) { namespace(:inner) {} }
279
+ inner = @config.namespaces[:outer].namespaces[:inner]
280
+ assert_nil inner.search_task(:first)
281
+ end
282
+
283
+ def test_top_should_return_self_if_self_is_top
284
+ assert_equal @config, @config.top
285
+ end
286
+
287
+ def test_top_should_return_parent_if_parent_is_top
288
+ @config.namespace(:outer) {}
289
+ assert_equal @config, @config.namespaces[:outer].top
290
+ end
291
+
292
+ def test_top_should_return_topmost_parent_if_self_is_deeply_nested
293
+ @config.namespace(:outer) { namespace(:middle) { namespace(:inner) {} } }
294
+ assert_equal @config, @config.namespaces[:outer].namespaces[:middle].namespaces[:inner].top
295
+ end
296
+
297
+ def test_find_task_should_return_nil_when_empty_inner_task
298
+ @config.namespace :outer do
299
+ namespace :inner do
300
+ end
301
+ end
302
+ assert_nil @config.find_task("outer::inner")
303
+ end
304
+
305
+ def test_kernel_method_clashing_should_not_affect_method_delegation_to_parent
306
+ @config.class.class_eval do
307
+ def some_weird_method() 'config' end
308
+ end
309
+
310
+ @config.namespace(:clash) {}
311
+ namespace = @config.namespaces[:clash]
312
+ assert_equal 'config', namespace.some_weird_method
313
+
314
+ Kernel.module_eval do
315
+ def some_weird_method() 'kernel' end
316
+ end
317
+
318
+ @config.namespace(:clash2) {}
319
+ namespace = @config.namespaces[:clash2]
320
+ assert_equal 'config', namespace.some_weird_method
321
+
322
+ Kernel.send :remove_method, :some_weird_method
323
+ @config.class.send :remove_method, :some_weird_method
324
+ end
325
+ end
@@ -0,0 +1,100 @@
1
+ require "utils"
2
+ require 'minestrone/task_definition'
3
+ require 'minestrone/configuration/servers'
4
+
5
+ class ConfigurationServersTest < Test::Unit::TestCase
6
+ class MockConfig
7
+ def initialize
8
+ initialize_servers
9
+ end
10
+
11
+ include Minestrone::Configuration::Servers
12
+ end
13
+
14
+ def setup
15
+ @config = MockConfig.new
16
+ @config.server "app1", :user => "deploy", :port => 2222, :ssh_options => { :forward_agent => true }
17
+ end
18
+
19
+ def teardown
20
+ ENV.delete('HOSTS')
21
+ ENV.delete('SERVER')
22
+ end
23
+
24
+ def test_resolved_server_should_return_the_configured_server
25
+ assert_equal "app1", @config.resolved_server.host
26
+ end
27
+
28
+ def test_server_should_keep_connection_options
29
+ server = @config.resolved_server
30
+ assert_equal "deploy", server.user
31
+ assert_equal 2222, server.port
32
+ assert_equal({ :forward_agent => true }, server.options[:ssh_options])
33
+ end
34
+
35
+ def test_server_environment_variable_should_replace_configured_host
36
+ ENV['SERVER'] = "override"
37
+ server = @config.resolved_server
38
+ assert_equal "override", server.host
39
+ assert_equal "deploy", server.user
40
+ assert_equal 2222, server.port
41
+ assert_equal({ :forward_agent => true }, server.options[:ssh_options])
42
+ end
43
+
44
+ def test_server_environment_variable_can_include_user_and_port
45
+ ENV['SERVER'] = "other@override:2022"
46
+ server = @config.resolved_server
47
+ assert_equal "override", server.host
48
+ assert_equal "other", server.user
49
+ assert_equal 2022, server.port
50
+ end
51
+
52
+ def test_server_environment_variable_must_not_be_blank
53
+ ENV['SERVER'] = " "
54
+ assert_raises(ArgumentError) { @config.resolved_server }
55
+ end
56
+
57
+ def test_hosts_environment_variable_should_replace_configured_host_as_fallback
58
+ ENV['HOSTS'] = "override"
59
+ server = @config.resolved_server
60
+ assert_equal "override", server.host
61
+ assert_equal "deploy", server.user
62
+ assert_equal 2222, server.port
63
+ assert_equal({ :forward_agent => true }, server.options[:ssh_options])
64
+ end
65
+
66
+ def test_server_environment_variable_should_take_precedence_over_hosts
67
+ ENV['SERVER'] = "override"
68
+ ENV['HOSTS'] = "fallback"
69
+ assert_equal "override", @config.resolved_server.host
70
+ end
71
+
72
+ def test_hosts_environment_variable_must_name_a_single_server
73
+ ENV['HOSTS'] = "app1,app2"
74
+ assert_raises(ArgumentError) { @config.resolved_server }
75
+ end
76
+
77
+ def test_host_environment_variable_should_not_replace_configured_host
78
+ ENV['HOST'] = "override"
79
+ assert_equal "app1", @config.resolved_server.host
80
+ end
81
+
82
+ def test_resolved_server_should_raise_when_no_server_is_configured
83
+ config = MockConfig.new
84
+ assert_raises(Minestrone::NoMatchingServersError) { config.resolved_server }
85
+ end
86
+
87
+ def test_server_should_reject_multiple_hosts
88
+ config = MockConfig.new
89
+ assert_raises(ArgumentError) { config.server "app1", "app2" }
90
+ end
91
+
92
+ def test_server_should_reject_comma_separated_hosts
93
+ config = MockConfig.new
94
+ assert_raises(ArgumentError) { config.server "app1,app2" }
95
+ end
96
+
97
+ def test_server_should_reject_a_second_definition
98
+ assert_raises(ArgumentError) { @config.server "app2" }
99
+ end
100
+ end