mbailey-capistrano 2.5.5

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 (105) hide show
  1. data/CHANGELOG.rdoc +761 -0
  2. data/Manifest +104 -0
  3. data/README.rdoc +66 -0
  4. data/Rakefile +34 -0
  5. data/bin/cap +4 -0
  6. data/bin/capify +78 -0
  7. data/examples/sample.rb +14 -0
  8. data/lib/capistrano/callback.rb +45 -0
  9. data/lib/capistrano/cli/execute.rb +84 -0
  10. data/lib/capistrano/cli/help.rb +125 -0
  11. data/lib/capistrano/cli/help.txt +75 -0
  12. data/lib/capistrano/cli/options.rb +224 -0
  13. data/lib/capistrano/cli/ui.rb +40 -0
  14. data/lib/capistrano/cli.rb +47 -0
  15. data/lib/capistrano/command.rb +283 -0
  16. data/lib/capistrano/configuration/actions/file_transfer.rb +47 -0
  17. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  18. data/lib/capistrano/configuration/actions/invocation.rb +293 -0
  19. data/lib/capistrano/configuration/callbacks.rb +148 -0
  20. data/lib/capistrano/configuration/connections.rb +200 -0
  21. data/lib/capistrano/configuration/execution.rb +132 -0
  22. data/lib/capistrano/configuration/loading.rb +197 -0
  23. data/lib/capistrano/configuration/namespaces.rb +197 -0
  24. data/lib/capistrano/configuration/roles.rb +73 -0
  25. data/lib/capistrano/configuration/servers.rb +85 -0
  26. data/lib/capistrano/configuration/variables.rb +127 -0
  27. data/lib/capistrano/configuration.rb +43 -0
  28. data/lib/capistrano/errors.rb +15 -0
  29. data/lib/capistrano/extensions.rb +57 -0
  30. data/lib/capistrano/logger.rb +59 -0
  31. data/lib/capistrano/processable.rb +53 -0
  32. data/lib/capistrano/recipes/compat.rb +32 -0
  33. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  34. data/lib/capistrano/recipes/deploy/local_dependency.rb +54 -0
  35. data/lib/capistrano/recipes/deploy/remote_dependency.rb +105 -0
  36. data/lib/capistrano/recipes/deploy/scm/accurev.rb +169 -0
  37. data/lib/capistrano/recipes/deploy/scm/base.rb +196 -0
  38. data/lib/capistrano/recipes/deploy/scm/bzr.rb +83 -0
  39. data/lib/capistrano/recipes/deploy/scm/cvs.rb +152 -0
  40. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  41. data/lib/capistrano/recipes/deploy/scm/git.rb +271 -0
  42. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +137 -0
  43. data/lib/capistrano/recipes/deploy/scm/none.rb +44 -0
  44. data/lib/capistrano/recipes/deploy/scm/perforce.rb +133 -0
  45. data/lib/capistrano/recipes/deploy/scm/subversion.rb +121 -0
  46. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  47. data/lib/capistrano/recipes/deploy/strategy/base.rb +79 -0
  48. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  49. data/lib/capistrano/recipes/deploy/strategy/copy.rb +210 -0
  50. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  51. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  52. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +56 -0
  53. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  54. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  55. data/lib/capistrano/recipes/deploy.rb +562 -0
  56. data/lib/capistrano/recipes/standard.rb +37 -0
  57. data/lib/capistrano/recipes/templates/maintenance.rhtml +53 -0
  58. data/lib/capistrano/recipes/upgrade.rb +33 -0
  59. data/lib/capistrano/role.rb +102 -0
  60. data/lib/capistrano/server_definition.rb +56 -0
  61. data/lib/capistrano/shell.rb +260 -0
  62. data/lib/capistrano/ssh.rb +99 -0
  63. data/lib/capistrano/task_definition.rb +70 -0
  64. data/lib/capistrano/transfer.rb +216 -0
  65. data/lib/capistrano/version.rb +18 -0
  66. data/lib/capistrano.rb +2 -0
  67. data/setup.rb +1346 -0
  68. data/test/cli/execute_test.rb +132 -0
  69. data/test/cli/help_test.rb +165 -0
  70. data/test/cli/options_test.rb +317 -0
  71. data/test/cli/ui_test.rb +28 -0
  72. data/test/cli_test.rb +17 -0
  73. data/test/command_test.rb +286 -0
  74. data/test/configuration/actions/file_transfer_test.rb +61 -0
  75. data/test/configuration/actions/inspect_test.rb +65 -0
  76. data/test/configuration/actions/invocation_test.rb +224 -0
  77. data/test/configuration/callbacks_test.rb +220 -0
  78. data/test/configuration/connections_test.rb +349 -0
  79. data/test/configuration/execution_test.rb +175 -0
  80. data/test/configuration/loading_test.rb +132 -0
  81. data/test/configuration/namespace_dsl_test.rb +311 -0
  82. data/test/configuration/roles_test.rb +144 -0
  83. data/test/configuration/servers_test.rb +121 -0
  84. data/test/configuration/variables_test.rb +184 -0
  85. data/test/configuration_test.rb +88 -0
  86. data/test/deploy/local_dependency_test.rb +76 -0
  87. data/test/deploy/remote_dependency_test.rb +114 -0
  88. data/test/deploy/scm/accurev_test.rb +23 -0
  89. data/test/deploy/scm/base_test.rb +55 -0
  90. data/test/deploy/scm/git_test.rb +167 -0
  91. data/test/deploy/scm/mercurial_test.rb +129 -0
  92. data/test/deploy/strategy/copy_test.rb +258 -0
  93. data/test/extensions_test.rb +69 -0
  94. data/test/fixtures/cli_integration.rb +5 -0
  95. data/test/fixtures/config.rb +5 -0
  96. data/test/fixtures/custom.rb +3 -0
  97. data/test/logger_test.rb +123 -0
  98. data/test/role_test.rb +11 -0
  99. data/test/server_definition_test.rb +121 -0
  100. data/test/shell_test.rb +90 -0
  101. data/test/ssh_test.rb +104 -0
  102. data/test/task_definition_test.rb +101 -0
  103. data/test/transfer_test.rb +160 -0
  104. data/test/utils.rb +38 -0
  105. metadata +205 -0
@@ -0,0 +1,175 @@
1
+ require "utils"
2
+ require 'capistrano/configuration/execution'
3
+ require 'capistrano/task_definition'
4
+
5
+ class ConfigurationExecutionTest < Test::Unit::TestCase
6
+ class MockConfig
7
+ attr_reader :tasks, :namespaces, :fully_qualified_name, :parent
8
+ attr_reader :state, :original_initialize_called
9
+ attr_accessor :logger, :default_task
10
+
11
+ def initialize(options={})
12
+ @original_initialize_called = true
13
+ @tasks = {}
14
+ @namespaces = {}
15
+ @state = {}
16
+ @fully_qualified_name = options[:fqn]
17
+ @parent = options[:parent]
18
+ @logger = options.delete(:logger)
19
+ end
20
+
21
+ include Capistrano::Configuration::Execution
22
+ end
23
+
24
+ def setup
25
+ @config = MockConfig.new(:logger => stub(:debug => nil, :info => nil, :important => nil))
26
+ @config.stubs(:search_task).returns(nil)
27
+ end
28
+
29
+ def test_initialize_should_initialize_collections
30
+ assert_nil @config.rollback_requests
31
+ assert @config.original_initialize_called
32
+ assert @config.task_call_frames.empty?
33
+ end
34
+
35
+ def test_execute_task_should_populate_call_stack
36
+ task = new_task @config, :testing
37
+ assert_nothing_raised { @config.execute_task(task) }
38
+ assert_equal %w(testing), @config.state[:testing][:stack]
39
+ assert_nil @config.state[:testing][:history]
40
+ assert @config.task_call_frames.empty?
41
+ end
42
+
43
+ def test_nested_execute_task_should_add_to_call_stack
44
+ testing = new_task @config, :testing
45
+ outer = new_task(@config, :outer) { execute_task(testing) }
46
+
47
+ assert_nothing_raised { @config.execute_task(outer) }
48
+ assert_equal %w(outer testing), @config.state[:testing][:stack]
49
+ assert_nil @config.state[:testing][:history]
50
+ assert @config.task_call_frames.empty?
51
+ end
52
+
53
+ def test_execute_task_should_execute_in_scope_of_tasks_parent
54
+ ns = stub("namespace", :tasks => {}, :default_task => nil, :fully_qualified_name => "ns")
55
+ ns.expects(:instance_eval)
56
+ testing = new_task ns, :testing
57
+ @config.execute_task(testing)
58
+ end
59
+
60
+ def test_transaction_outside_of_task_should_raise_exception
61
+ assert_raises(ScriptError) { @config.transaction {} }
62
+ end
63
+
64
+ def test_transaction_without_block_should_raise_argument_error
65
+ testing = new_task(@config, :testing) { transaction }
66
+ assert_raises(ArgumentError) { @config.execute_task(testing) }
67
+ end
68
+
69
+ def test_transaction_should_initialize_transaction_history
70
+ @config.state[:inspector] = stack_inspector
71
+ testing = new_task(@config, :testing) { transaction { instance_eval(&state[:inspector]) } }
72
+ @config.execute_task(testing)
73
+ assert_equal [], @config.state[:testing][:history]
74
+ end
75
+
76
+ def test_transaction_from_within_transaction_should_not_start_new_transaction
77
+ third = new_task(@config, :third, &stack_inspector)
78
+ second = new_task(@config, :second) { transaction { execute_task(third) } }
79
+ first = new_task(@config, :first) { transaction { execute_task(second) } }
80
+ # kind of fragile...not sure how else to check that transaction was only
81
+ # really run twice...but if the transaction was REALLY run, logger.info
82
+ # will be called once when it starts, and once when it finishes.
83
+ @config.logger = mock()
84
+ @config.logger.stubs(:debug)
85
+ @config.logger.expects(:info).times(2)
86
+ @config.execute_task(first)
87
+ end
88
+
89
+ def test_on_rollback_should_have_no_effect_outside_of_transaction
90
+ aaa = new_task(@config, :aaa) { on_rollback { state[:rollback] = true }; raise "boom" }
91
+ assert_raises(RuntimeError) { @config.execute_task(aaa) }
92
+ assert_nil @config.state[:rollback]
93
+ end
94
+
95
+ def test_exception_raised_in_transaction_should_call_all_registered_rollback_handlers_in_reverse_order
96
+ aaa = new_task(@config, :aaa) { on_rollback { (state[:rollback] ||= []) << :aaa } }
97
+ bbb = new_task(@config, :bbb) { on_rollback { (state[:rollback] ||= []) << :bbb } }
98
+ ccc = new_task(@config, :ccc) {}
99
+ ddd = new_task(@config, :ddd) { on_rollback { (state[:rollback] ||= []) << :ddd }; execute_task(bbb); execute_task(ccc) }
100
+ eee = new_task(@config, :eee) { transaction { execute_task(ddd); execute_task(aaa); raise "boom" } }
101
+ assert_raises(RuntimeError) do
102
+ @config.execute_task(eee)
103
+ end
104
+ assert_equal [:aaa, :bbb, :ddd], @config.state[:rollback]
105
+ assert_nil @config.rollback_requests
106
+ assert @config.task_call_frames.empty?
107
+ end
108
+
109
+ def test_exception_during_rollback_should_simply_be_logged_and_ignored
110
+ aaa = new_task(@config, :aaa) { on_rollback { state[:aaa] = true; raise LoadError, "ouch" }; execute_task(bbb) }
111
+ bbb = new_task(@config, :bbb) { raise MadError, "boom" }
112
+ ccc = new_task(@config, :ccc) { transaction { execute_task(aaa) } }
113
+ assert_raises(NameError) do
114
+ @config.execute_task(ccc)
115
+ end
116
+ assert @config.state[:aaa]
117
+ end
118
+
119
+ def test_on_rollback_called_twice_should_result_in_last_rollback_block_being_effective
120
+ aaa = new_task(@config, :aaa) do
121
+ transaction do
122
+ on_rollback { (state[:rollback] ||= []) << :first }
123
+ on_rollback { (state[:rollback] ||= []) << :second }
124
+ raise "boom"
125
+ end
126
+ end
127
+
128
+ assert_raises(RuntimeError) do
129
+ @config.execute_task(aaa)
130
+ end
131
+
132
+ assert_equal [:second], @config.state[:rollback]
133
+ end
134
+
135
+ def test_find_and_execute_task_should_raise_error_when_task_cannot_be_found
136
+ @config.expects(:find_task).with("path:to:task").returns(nil)
137
+ assert_raises(Capistrano::NoSuchTaskError) { @config.find_and_execute_task("path:to:task") }
138
+ end
139
+
140
+ def test_find_and_execute_task_should_execute_task_when_task_is_found
141
+ @config.expects(:find_task).with("path:to:task").returns(:found)
142
+ @config.expects(:execute_task).with(:found)
143
+ assert_nothing_raised { @config.find_and_execute_task("path:to:task") }
144
+ end
145
+
146
+ def test_find_and_execute_task_with_before_option_should_trigger_callback
147
+ @config.expects(:find_task).with("path:to:task").returns(:found)
148
+ @config.expects(:trigger).with(:incoming, :found)
149
+ @config.expects(:execute_task).with(:found)
150
+ @config.find_and_execute_task("path:to:task", :before => :incoming)
151
+ end
152
+
153
+ def test_find_and_execute_task_with_after_option_should_trigger_callback
154
+ @config.expects(:find_task).with("path:to:task").returns(:found)
155
+ @config.expects(:trigger).with(:outgoing, :found)
156
+ @config.expects(:execute_task).with(:found)
157
+ @config.find_and_execute_task("path:to:task", :after => :outgoing)
158
+ end
159
+
160
+ private
161
+
162
+ def stack_inspector
163
+ Proc.new do
164
+ (state[:trail] ||= []) << current_task.fully_qualified_name
165
+ data = state[current_task.name] = {}
166
+ data[:stack] = task_call_frames.map { |frame| frame.task.fully_qualified_name }
167
+ data[:history] = rollback_requests && rollback_requests.map { |frame| frame.task.fully_qualified_name }
168
+ end
169
+ end
170
+
171
+ def new_task(namespace, name, options={}, &block)
172
+ block ||= stack_inspector
173
+ namespace.tasks[name] = Capistrano::TaskDefinition.new(name, namespace, &block)
174
+ end
175
+ end
@@ -0,0 +1,132 @@
1
+ require "utils"
2
+ require 'capistrano/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
+ end
12
+
13
+ def ping!(value)
14
+ @ping = value
15
+ end
16
+
17
+ include Capistrano::Configuration::Loading
18
+ end
19
+
20
+ def setup
21
+ @config = MockConfig.new
22
+ end
23
+
24
+ def teardown
25
+ MockConfig.instance = nil
26
+ $LOADED_FEATURES.delete_if { |a| a =~ /fixtures\/custom\.rb$/ }
27
+ end
28
+
29
+ def test_initialize_should_init_collections
30
+ assert @config.original_initialize_called
31
+ assert @config.load_paths.include?(".")
32
+ assert @config.load_paths.detect { |v| v =~ /capistrano\/recipes$/ }
33
+ end
34
+
35
+ def test_load_with_options_and_block_should_raise_argument_error
36
+ assert_raises(ArgumentError) do
37
+ @config.load(:string => "foo") { something }
38
+ end
39
+ end
40
+
41
+ def test_load_with_arguments_and_block_should_raise_argument_error
42
+ assert_raises(ArgumentError) do
43
+ @config.load("foo") { something }
44
+ end
45
+ end
46
+
47
+ def test_load_from_string_should_eval_in_config_scope
48
+ @config.load :string => "ping! :here"
49
+ assert_equal :here, @config.ping
50
+ end
51
+
52
+ def test_load_from_file_shoudld_respect_load_path
53
+ File.stubs(:file?).returns(false)
54
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
55
+ File.stubs(:read).with("custom/path/for/file.rb").returns("ping! :here")
56
+
57
+ @config.load_paths << "custom/path/for"
58
+ @config.load :file => "file.rb"
59
+
60
+ assert_equal :here, @config.ping
61
+ end
62
+
63
+ def test_load_from_file_should_respect_load_path_and_appends_rb
64
+ File.stubs(:file?).returns(false)
65
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
66
+ File.stubs(:read).with("custom/path/for/file.rb").returns("ping! :here")
67
+
68
+ @config.load_paths << "custom/path/for"
69
+ @config.load :file => "file"
70
+
71
+ assert_equal :here, @config.ping
72
+ end
73
+
74
+ def test_load_from_file_should_raise_load_error_if_file_cannot_be_found
75
+ File.stubs(:file?).returns(false)
76
+ assert_raises(LoadError) do
77
+ @config.load :file => "file"
78
+ end
79
+ end
80
+
81
+ def test_load_from_proc_should_eval_proc_in_config_scope
82
+ @config.load :proc => Proc.new { ping! :here }
83
+ assert_equal :here, @config.ping
84
+ end
85
+
86
+ def test_load_with_block_should_treat_block_as_proc_parameter
87
+ @config.load { ping! :here }
88
+ assert_equal :here, @config.ping
89
+ end
90
+
91
+ def test_load_with_unrecognized_option_should_raise_argument_error
92
+ assert_raises(ArgumentError) do
93
+ @config.load :url => "http://www.load-this.test"
94
+ end
95
+ end
96
+
97
+ def test_load_with_arguments_should_treat_arguments_as_files
98
+ File.stubs(:file?).returns(false)
99
+ File.stubs(:file?).with("./first.rb").returns(true)
100
+ File.stubs(:file?).with("./second.rb").returns(true)
101
+ File.stubs(:read).with("./first.rb").returns("ping! 'this'")
102
+ File.stubs(:read).with("./second.rb").returns("ping << 'that'")
103
+ assert_nothing_raised { @config.load "first", "second" }
104
+ assert_equal "thisthat", @config.ping
105
+ end
106
+
107
+ def test_require_from_config_should_load_file_in_config_scope
108
+ assert_nothing_raised do
109
+ @config.require "#{File.dirname(__FILE__)}/../fixtures/custom"
110
+ end
111
+ assert_equal :custom, @config.ping
112
+ end
113
+
114
+ def test_require_without_config_should_raise_load_error
115
+ assert_raises(LoadError) do
116
+ require "#{File.dirname(__FILE__)}/../fixtures/custom"
117
+ end
118
+ end
119
+
120
+ def test_require_from_config_should_return_false_when_called_a_second_time_with_same_args
121
+ assert @config.require("#{File.dirname(__FILE__)}/../fixtures/custom")
122
+ assert_equal false, @config.require("#{File.dirname(__FILE__)}/../fixtures/custom")
123
+ end
124
+
125
+ def test_require_in_multiple_instances_should_load_recipes_in_each_instance
126
+ config2 = MockConfig.new
127
+ @config.require "#{File.dirname(__FILE__)}/../fixtures/custom"
128
+ config2.require "#{File.dirname(__FILE__)}/../fixtures/custom"
129
+ assert_equal :custom, @config.ping
130
+ assert_equal :custom, config2.ping
131
+ end
132
+ end
@@ -0,0 +1,311 @@
1
+ require "utils"
2
+ require 'capistrano/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
+ end
12
+
13
+ include Capistrano::Configuration::Namespaces
14
+ end
15
+
16
+ def setup
17
+ @config = MockConfig.new
18
+ end
19
+
20
+ def test_initialize_should_initialize_collections
21
+ assert @config.original_initialize_called
22
+ assert @config.tasks.empty?
23
+ assert @config.namespaces.empty?
24
+ end
25
+
26
+ def test_unqualified_task_should_define_task_at_top_namespace
27
+ assert !@config.tasks.key?(:testing)
28
+ @config.task(:testing) { puts "something" }
29
+ assert @config.tasks.key?(:testing)
30
+ end
31
+
32
+ def test_qualification_should_define_task_within_namespace
33
+ @config.namespace(:testing) do
34
+ task(:nested) { puts "nested" }
35
+ end
36
+
37
+ assert !@config.tasks.key?(:nested)
38
+ assert @config.namespaces.key?(:testing)
39
+ assert @config.namespaces[:testing].tasks.key?(:nested)
40
+ end
41
+
42
+ def test_namespace_within_namespace_should_define_task_within_nested_namespace
43
+ @config.namespace :outer do
44
+ namespace :inner do
45
+ task :nested do
46
+ puts "nested"
47
+ end
48
+ end
49
+ end
50
+
51
+ assert !@config.tasks.key?(:nested)
52
+ assert @config.namespaces.key?(:outer)
53
+ assert @config.namespaces[:outer].namespaces.key?(:inner)
54
+ assert @config.namespaces[:outer].namespaces[:inner].tasks.key?(:nested)
55
+ end
56
+
57
+ def test_pending_desc_should_apply_only_to_immediately_subsequent_task
58
+ @config.desc "A description"
59
+ @config.task(:testing) { puts "foo" }
60
+ @config.task(:another) { puts "bar" }
61
+ assert_equal "A description", @config.tasks[:testing].desc
62
+ assert_nil @config.tasks[:another].desc
63
+ end
64
+
65
+ def test_pending_desc_should_apply_only_to_next_task_in_any_namespace
66
+ @config.desc "A description"
67
+ @config.namespace(:outer) { task(:testing) { puts "foo" } }
68
+ assert_equal "A description", @config.namespaces[:outer].tasks[:testing].desc
69
+ end
70
+
71
+ def test_defining_task_without_block_should_raise_error
72
+ assert_raises(ArgumentError) do
73
+ @config.task(:testing)
74
+ end
75
+ end
76
+
77
+ def test_defining_task_that_shadows_existing_method_should_raise_error
78
+ assert_raises(ArgumentError) do
79
+ @config.task(:sprintf) { puts "foo" }
80
+ end
81
+ end
82
+
83
+ def test_defining_task_that_shadows_existing_namespace_should_raise_error
84
+ @config.namespace(:outer) {}
85
+ assert_raises(ArgumentError) do
86
+ @config.task(:outer) { puts "foo" }
87
+ end
88
+ end
89
+
90
+ def test_defining_namespace_that_shadows_existing_method_should_raise_error
91
+ assert_raises(ArgumentError) do
92
+ @config.namespace(:sprintf) {}
93
+ end
94
+ end
95
+
96
+ def test_defining_namespace_that_shadows_existing_task_should_raise_error
97
+ @config.task(:testing) { puts "foo" }
98
+ assert_raises(ArgumentError) do
99
+ @config.namespace(:testing) {}
100
+ end
101
+ end
102
+
103
+ def test_defining_task_that_shadows_existing_task_should_not_raise_error
104
+ @config.task(:original) { puts "foo" }
105
+ assert_nothing_raised do
106
+ @config.task(:original) { puts "bar" }
107
+ end
108
+ end
109
+
110
+ def test_defining_ask_should_add_task_as_method
111
+ assert !@config.methods.any? { |m| m.to_sym == :original }
112
+ @config.task(:original) { puts "foo" }
113
+ assert @config.methods.any? { |m| m.to_sym == :original }
114
+ end
115
+
116
+ def test_calling_defined_task_should_delegate_to_execute_task
117
+ @config.task(:original) { puts "foo" }
118
+ @config.expects(:execute_task).with(@config.tasks[:original])
119
+ @config.original
120
+ end
121
+
122
+ def test_role_inside_namespace_should_raise_error
123
+ assert_raises(NotImplementedError) do
124
+ @config.namespace(:outer) do
125
+ role :app, "hello"
126
+ end
127
+ end
128
+ end
129
+
130
+ def test_name_for_top_level_should_be_nil
131
+ assert_nil @config.name
132
+ end
133
+
134
+ def test_parent_for_top_level_should_be_nil
135
+ assert_nil @config.parent
136
+ end
137
+
138
+ def test_fqn_for_top_level_should_be_nil
139
+ assert_nil @config.fully_qualified_name
140
+ end
141
+
142
+ def test_fqn_for_namespace_should_be_the_name_of_the_namespace
143
+ @config.namespace(:outer) {}
144
+ assert_equal "outer", @config.namespaces[:outer].fully_qualified_name
145
+ end
146
+
147
+ def test_parent_for_namespace_should_be_the_top_level
148
+ @config.namespace(:outer) {}
149
+ assert_equal @config, @config.namespaces[:outer].parent
150
+ end
151
+
152
+ def test_fqn_for_nested_namespace_should_be_color_delimited
153
+ @config.namespace(:outer) { namespace(:inner) {} }
154
+ assert_equal "outer:inner", @config.namespaces[:outer].namespaces[:inner].fully_qualified_name
155
+ end
156
+
157
+ def test_parent_for_nested_namespace_should_be_the_nesting_namespace
158
+ @config.namespace(:outer) { namespace(:inner) {} }
159
+ assert_equal @config.namespaces[:outer], @config.namespaces[:outer].namespaces[:inner].parent
160
+ end
161
+
162
+ def test_find_task_should_dereference_nested_tasks
163
+ @config.namespace(:outer) do
164
+ namespace(:inner) { task(:nested) { puts "nested" } }
165
+ end
166
+
167
+ task = @config.find_task("outer:inner:nested")
168
+ assert_not_nil task
169
+ assert_equal "outer:inner:nested", task.fully_qualified_name
170
+ end
171
+
172
+ def test_find_task_should_return_nil_if_no_task_matches
173
+ assert_nil @config.find_task("outer:inner:nested")
174
+ end
175
+
176
+ def test_find_task_should_return_default_if_deferences_to_namespace_and_namespace_has_default
177
+ @config.namespace(:outer) do
178
+ namespace(:inner) { task(:default) { puts "nested" } }
179
+ end
180
+
181
+ task = @config.find_task("outer:inner")
182
+ assert_not_nil task
183
+ assert_equal :default, task.name
184
+ assert_equal "outer:inner", task.namespace.fully_qualified_name
185
+ end
186
+
187
+ def test_find_task_should_return_nil_if_deferences_to_namespace_and_namespace_has_no_default
188
+ @config.namespace(:outer) do
189
+ namespace(:inner) { task(:nested) { puts "nested" } }
190
+ end
191
+
192
+ assert_nil @config.find_task("outer:inner")
193
+ end
194
+
195
+ def test_default_task_should_return_nil_for_top_level
196
+ @config.task(:default) {}
197
+ assert_nil @config.default_task
198
+ end
199
+
200
+ def test_default_task_should_return_nil_for_namespace_without_default
201
+ @config.namespace(:outer) { task(:nested) { puts "nested" } }
202
+ assert_nil @config.namespaces[:outer].default_task
203
+ end
204
+
205
+ def test_default_task_should_return_task_for_namespace_with_default
206
+ @config.namespace(:outer) { task(:default) { puts "nested" } }
207
+ task = @config.namespaces[:outer].default_task
208
+ assert_not_nil task
209
+ assert_equal :default, task.name
210
+ end
211
+
212
+ def test_task_list_should_return_only_tasks_immediately_within_namespace
213
+ @config.task(:first) { puts "here" }
214
+ @config.namespace(:outer) do
215
+ task(:second) { puts "here" }
216
+ namespace(:inner) do
217
+ task(:third) { puts "here" }
218
+ end
219
+ end
220
+
221
+ assert_equal %w(first), @config.task_list.map { |t| t.fully_qualified_name }
222
+ end
223
+
224
+ def test_task_list_with_all_should_return_all_tasks_under_this_namespace_recursively
225
+ @config.task(:first) { puts "here" }
226
+ @config.namespace(:outer) do
227
+ task(:second) { puts "here" }
228
+ namespace(:inner) do
229
+ task(:third) { puts "here" }
230
+ end
231
+ end
232
+
233
+ assert_equal %w(first outer:inner:third outer:second), @config.task_list(:all).map { |t| t.fully_qualified_name }.sort
234
+ end
235
+
236
+ def test_namespace_should_respond_to_its_parents_methods
237
+ @config.namespace(:outer) {}
238
+ ns = @config.namespaces[:outer]
239
+ assert ns.respond_to?(:original_initialize_called)
240
+ end
241
+
242
+ def test_namespace_should_accept_respond_to_with_include_priv_parameter
243
+ @config.namespace(:outer) {}
244
+ ns = @config.namespaces[:outer]
245
+ assert ns.respond_to?(:original_initialize_called, true)
246
+ end
247
+
248
+ def test_namespace_should_delegate_unknown_messages_to_its_parent
249
+ @config.namespace(:outer) {}
250
+ ns = @config.namespaces[:outer]
251
+ assert ns.original_initialize_called
252
+ end
253
+
254
+ def test_namespace_should_not_understand_messages_that_neither_it_nor_its_parent_understands
255
+ @config.namespace(:outer) {}
256
+ ns = @config.namespaces[:outer]
257
+ assert_raises(NoMethodError) { ns.alskdfjlsf }
258
+ end
259
+
260
+ def test_search_task_should_find_tasks_in_current_namespace
261
+ @config.namespace(:outer) do
262
+ namespace(:inner) do
263
+ task(:third) { puts "here" }
264
+ end
265
+ end
266
+
267
+ inner = @config.namespaces[:outer].namespaces[:inner]
268
+ assert_equal inner.tasks[:third], inner.search_task(:third)
269
+ end
270
+
271
+ def test_search_task_should_find_tasks_in_parent_namespace
272
+ @config.task(:first) { puts "here" }
273
+ @config.namespace(:outer) do
274
+ task(:second) { puts "here" }
275
+ namespace(:inner) do
276
+ task(:third) { puts "here" }
277
+ end
278
+ end
279
+
280
+ inner = @config.namespaces[:outer].namespaces[:inner]
281
+ assert_equal @config.tasks[:first], inner.search_task(:first)
282
+ end
283
+
284
+ def test_search_task_should_return_nil_if_no_tasks_are_found
285
+ @config.namespace(:outer) { namespace(:inner) {} }
286
+ inner = @config.namespaces[:outer].namespaces[:inner]
287
+ assert_nil inner.search_task(:first)
288
+ end
289
+
290
+ def test_top_should_return_self_if_self_is_top
291
+ assert_equal @config, @config.top
292
+ end
293
+
294
+ def test_top_should_return_parent_if_parent_is_top
295
+ @config.namespace(:outer) {}
296
+ assert_equal @config, @config.namespaces[:outer].top
297
+ end
298
+
299
+ def test_top_should_return_topmost_parent_if_self_is_deeply_nested
300
+ @config.namespace(:outer) { namespace(:middle) { namespace(:inner) {} } }
301
+ assert_equal @config, @config.namespaces[:outer].namespaces[:middle].namespaces[:inner].top
302
+ end
303
+
304
+ def test_find_task_should_return_nil_when_empty_inner_task
305
+ @config.namespace :outer do
306
+ namespace :inner do
307
+ end
308
+ end
309
+ assert_nil @config.find_task("outer::inner")
310
+ end
311
+ end