taketo 0.1.3 → 0.2.0.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +8 -0
  3. data/README.md +16 -1
  4. data/Rakefile +1 -0
  5. data/VERSION +1 -1
  6. data/bin/taketo +17 -89
  7. data/lib/taketo/actions/base_action.rb +29 -0
  8. data/lib/taketo/actions/generate_ssh_config.rb +22 -0
  9. data/lib/taketo/actions/group_action.rb +15 -0
  10. data/lib/taketo/actions/list.rb +22 -0
  11. data/lib/taketo/actions/login.rb +40 -0
  12. data/lib/taketo/actions/matches.rb +28 -0
  13. data/lib/taketo/actions/node_action.rb +15 -0
  14. data/lib/taketo/actions/server_action.rb +14 -0
  15. data/lib/taketo/actions/view.rb +24 -0
  16. data/lib/taketo/actions.rb +21 -0
  17. data/lib/taketo/associated_nodes.rb +4 -0
  18. data/lib/taketo/commands.rb +2 -1
  19. data/lib/taketo/config_validator.rb +4 -0
  20. data/lib/taketo/config_visitor.rb +3 -1
  21. data/lib/taketo/constructs/config.rb +2 -1
  22. data/lib/taketo/constructs/environment.rb +9 -0
  23. data/lib/taketo/constructs/group.rb +20 -0
  24. data/lib/taketo/constructs/project.rb +2 -1
  25. data/lib/taketo/constructs/server.rb +1 -1
  26. data/lib/taketo/constructs.rb +1 -0
  27. data/lib/taketo/constructs_factory.rb +4 -0
  28. data/lib/taketo/destination_matcher.rb +4 -4
  29. data/lib/taketo/dsl.rb +18 -17
  30. data/lib/taketo/group_list_visitor.rb +11 -0
  31. data/lib/taketo/group_resolver.rb +12 -0
  32. data/lib/taketo/{destination_resolver.rb → node_resolver.rb} +5 -27
  33. data/lib/taketo/server_resolver.rb +29 -0
  34. data/spec/acceptance/command_spec.rb +2 -1
  35. data/spec/acceptance/completion_spec.rb +26 -9
  36. data/spec/acceptance/config_dsl_spec.rb +74 -13
  37. data/spec/acceptance/config_validation_spec.rb +20 -5
  38. data/spec/acceptance/connect_to_server_spec.rb +6 -3
  39. data/spec/acceptance/error_handling_spec.rb +2 -2
  40. data/spec/acceptance/generate_ssh_config_spec.rb +1 -1
  41. data/spec/acceptance/help_spec.rb +4 -2
  42. data/spec/acceptance/location_spec.rb +2 -1
  43. data/spec/acceptance_spec_helper.rb +1 -1
  44. data/spec/lib/taketo/actions_spec.rb +17 -0
  45. data/spec/lib/taketo/associated_nodes_spec.rb +34 -0
  46. data/spec/lib/taketo/config_validator_spec.rb +1 -1
  47. data/spec/lib/taketo/constructs/config_spec.rb +4 -1
  48. data/spec/lib/taketo/constructs/environment_spec.rb +6 -1
  49. data/spec/lib/taketo/constructs/group_spec.rb +30 -0
  50. data/spec/lib/taketo/constructs/project_spec.rb +2 -0
  51. data/spec/lib/taketo/constructs/server_spec.rb +6 -2
  52. data/spec/lib/taketo/constructs_factory_spec.rb +5 -0
  53. data/spec/lib/taketo/dsl_spec.rb +86 -74
  54. data/spec/lib/taketo/group_list_visitor_spec.rb +20 -0
  55. data/spec/lib/taketo/group_resolver_spec.rb +59 -0
  56. data/spec/lib/taketo/{destination_resolver_spec.rb → server_resolver_spec.rb} +3 -29
  57. data/spec/support/helpers/construct_spec_helper.rb +9 -0
  58. data/spec/support/helpers/dsl_spec_helper.rb +31 -9
  59. data/spec/support/matchers/enclose_scope_matcher.rb +15 -7
  60. metadata +41 -20
@@ -97,5 +97,39 @@ describe "AssociatedNodes" do
97
97
  expect { construct.has_nodes?(:quack) }.to raise_error NodesNotDefinedError
98
98
  end
99
99
  end
100
+
101
+ describe "#has_deeply_nested_nodes?" do
102
+ class TestNestedNodes
103
+ include AssociatedNodes
104
+
105
+ def name; :foo; end
106
+
107
+ has_nodes :foos, :foo
108
+ has_nodes :bars, :bar
109
+ end
110
+
111
+ subject(:construct) { TestNestedNodes.new }
112
+ let(:foo) { TestNestedNodes.new }
113
+
114
+ context "directly nested nodes" do
115
+ it "returns true when present" do
116
+ construct.nodes(:foos) << foo
117
+ expect(construct).to have_deeply_nested_nodes(:foos)
118
+ end
119
+ end
120
+
121
+ context "indirectly nested nodes" do
122
+ before(:each) { construct.nodes(:foos) << foo }
123
+
124
+ it "returns true when present" do
125
+ foo.nodes(:bars) << stub(:Bar, :name => :bar)
126
+ expect(construct).to have_deeply_nested_nodes(:bars)
127
+ end
128
+
129
+ it "returns false when not present" do
130
+ expect(construct).not_to have_deeply_nested_nodes(:bars)
131
+ end
132
+ end
133
+ end
100
134
  end
101
135
 
@@ -18,7 +18,7 @@ end
18
18
  describe "ConfigValidator::ConfigValidatorVisitor" do
19
19
  subject(:visitor) { ConfigValidator::ConfigValidatorVisitor.new }
20
20
 
21
- { :Config => nil, :Project => "my_project" }.each do |node_type, path|
21
+ { :Config => nil, :Project => "my_project", :Group => "my_group" }.each do |node_type, path|
22
22
  it "requires #{node_type} to have servers" do
23
23
  node = stub(node_type, :has_servers? => false, :path => path)
24
24
  error_message = /#{path ? path + ": " : ""}no servers/
@@ -5,10 +5,13 @@ require 'taketo/constructs/config'
5
5
  include Taketo
6
6
 
7
7
  describe "Config" do
8
- subject { Taketo::Constructs::Config.new }
8
+ subject(:config) { Taketo::Constructs::Config.new }
9
9
 
10
+ it_behaves_like "a construct with nodes", :groups, :group
10
11
  it_behaves_like "a construct with nodes", :projects, :project
11
12
 
12
13
  it { should have_accessor(:default_destination) }
14
+
15
+ it_behaves_like "a node with servers", :servers, :server
13
16
  end
14
17
 
@@ -11,12 +11,17 @@ describe "Environment" do
11
11
  expect(environment.name).to eq(:foo)
12
12
  end
13
13
 
14
- it_behaves_like "a construct with nodes", :servers, :server
14
+ it_behaves_like "a construct with nodes", :groups, :group
15
+ it_behaves_like "a node with servers"
15
16
 
16
17
  specify "#project_name returns project name" do
17
18
  environment.parent = Taketo::Constructs::Project.new("TheProject")
18
19
  expect(environment.project_name).to eq("TheProject")
19
20
  end
21
+
22
+ specify "#rails_env returns name as string" do
23
+ environment.rails_env.should == "foo"
24
+ end
20
25
  end
21
26
 
22
27
 
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'support/helpers/construct_spec_helper'
3
+ require 'taketo/constructs/group'
4
+
5
+ include Taketo
6
+
7
+ describe "Group" do
8
+ subject(:group) { Taketo::Constructs::Group.new(:foo) }
9
+
10
+ it "has name" do
11
+ expect(group.name).to eq(:foo)
12
+ end
13
+
14
+ describe "#rails_env" do
15
+ it "returns parent's #rails_env" do
16
+ group.parent = stub(:Environment, :rails_env => "bar")
17
+ expect(group.rails_env).to eq("bar")
18
+ end
19
+
20
+ it "does not fail if parent does not provide #rails_env" do
21
+ group.parent = 1
22
+ expect(group.rails_env).to eq(nil)
23
+ end
24
+ end
25
+
26
+ it_behaves_like "a node with servers"
27
+ end
28
+
29
+
30
+
@@ -12,5 +12,7 @@ describe "Project" do
12
12
  end
13
13
 
14
14
  it_behaves_like "a construct with nodes", :environments, :environment
15
+ it_behaves_like "a construct with nodes", :groups, :group
16
+ it_behaves_like "a node with servers"
15
17
  end
16
18
 
@@ -48,12 +48,16 @@ describe "Server" do
48
48
  end
49
49
 
50
50
  describe "#parent=" do
51
- let(:environment) { environment = Taketo::Constructs::Environment.new(:the_environment) }
51
+ let(:environment) { stub(:Environment, :rails_env => 'the_env') }
52
52
 
53
53
  it "sets RAILS_ENV environment variable" do
54
54
  server.environment_variables.should == {}
55
55
  server.parent = environment
56
- expect(server.environment_variables[:RAILS_ENV]).to eq(environment.name.to_s)
56
+ expect(server.environment_variables[:RAILS_ENV]).to eq(environment.rails_env)
57
+ end
58
+
59
+ it "does not fail if parent doesn't provide #rails_env" do
60
+ expect { server.parent = 1 }.not_to raise_error
57
61
  end
58
62
  end
59
63
 
@@ -33,6 +33,11 @@ describe "ConstructsFactory" do
33
33
  expect(server).to be_an_instance_of(Taketo::Constructs::Server)
34
34
  end
35
35
 
36
+ specify "#create_group creates a group object" do
37
+ group = factory.create_group(:foo)
38
+ expect(group).to be_an_instance_of(Taketo::Constructs::Group)
39
+ end
40
+
36
41
  specify "#create_command creates a command object" do
37
42
  command = factory.create_command(:foo)
38
43
  expect(command).to be_an_instance_of(Taketo::Constructs::Command)
@@ -8,63 +8,67 @@ describe "DSL" do
8
8
  extend DSLSpec
9
9
  include DSLSpec
10
10
 
11
- shared_examples "a scoped construct" do |name, parents, with_block|
11
+ shared_examples_for "a scoped construct" do |name, parents, with_block|
12
12
  parents = Array(parents)
13
13
 
14
14
  parents.each do |parent_scope_name|
15
- parent_scope = scopes[parent_scope_name]
16
- it { should be_appropriate_construct(name, :foo).with_block(with_block).under(parent_scope) }
15
+ scopes[parent_scope_name].each do |parent_scope_variant|
16
+ it { should be_appropriate_construct(name, :foo).with_block(with_block).under(parent_scope_variant) }
17
+ end
17
18
  end
18
19
 
19
- scopes.except(*parents).each do |inappropriate_scope|
20
- it { should_not be_appropriate_construct(name, :foo).with_block(with_block).under(inappropriate_scope) }
20
+ scopes.except(*parents).each do |inappropriate_scopes|
21
+ inappropriate_scopes.each do |inappropriate_scope_variant|
22
+ it { should_not be_appropriate_construct(name, :foo).with_block(with_block).under(inappropriate_scope_variant) }
23
+ end
21
24
  end
22
25
  end
23
26
 
24
- shared_examples "a scope" do |scope_name, parent_scope_names|
27
+ shared_examples_for "a scope" do |scope_name, parent_scope_names|
25
28
  it_behaves_like "a scoped construct", scope_name, Array(parent_scope_names), true
26
29
 
27
30
  Array(parent_scope_names).each do |parent_scope_name|
28
- parent_scope = scopes[parent_scope_name]
29
-
30
- it { should enclose_scope(scope_name).under(parent_scope) }
31
-
32
- it "creates a #{scope_name} and set it as current scope object" do # it "creates project and set it as current scope object"
33
- dsl(parent_scope, factory.create(parent_scope_name)) do |c| # dsl([:config], factory.create(:config)) do |c|
34
- stub_find_or_create_scope_object(c, scope_name, :bar) # stub_find_or_create_scope_object(c, :project, :bar)
35
- c.send(scope_name, :bar) do # c.project(:bar) do
36
- expect(c.current_scope_object).not_to be_nil # expect(c.current_scope_object).not_to be_nil
37
- expect(c.current_scope_object).to eq(factory.send(scope_name)) # expect(c.current_scope_object).to eq(factory.project)
38
- end # end
39
- end # end
40
- end # end
41
-
42
- it "does not leak #{scope_name} as current scope object" do # it "does not leak project as current scope object"
43
- dsl(parent_scope, factory.create(parent_scope_name)) do |c| # dsl([:config], factory.create(:config)) do |c|
44
- stub_find_or_create_scope_object(c, scope_name, :bar) # stub_find_or_create_scope_object(c, :project, :bar)
45
- c.send(scope_name, :bar) do # c.project(:bar) do
46
- expect(c.current_scope_object).to eq(factory.send(scope_name)) # expect(c.current_scope_object).to eq(factory.project)
47
- end # end
48
- expect(c.current_scope_object).not_to eq(factory.send(scope_name)) # expect(c.current_scope_object).not_to eq(factory.project)
49
- end # end
50
- end # end
51
-
52
- it "adds a #{scope_name} to the #{parent_scope_name}'s #{scope_name}s collection" do # it "adds a project to the config's projects collection" do
53
- dsl(parent_scope, factory.create(parent_scope_name)) do |c| # dsl([:config], factory.create(:config)) do |c|
54
- stub_find_or_create_scope_object(c, scope_name, :bar) # stub_find_or_create_scope_object(c, :project, :bar)
55
- c.current_scope_object.should_receive("append_#{scope_name}"). # c.current_scope_object.should_receive(:append_project).
56
- with(factory.send(scope_name)) # with(factory.project)
57
- c.send(scope_name, :bar) {} # c.project(:bar) {}
58
- end # end
59
- end # end
60
-
61
- it "sets #{scope_name}'s parent to the #{parent_scope_name} scope object" do # it "sets project's parent to the config scope object" do
62
- dsl(parent_scope, factory.create(parent_scope_name)) do |c| # dsl([:config], factory.create(:config)) do |c|
63
- stub_find_or_create_scope_object(c, scope_name, :bar) # stub_find_or_create_scope_object(c, :project, :bar)
64
- factory.send(scope_name).should_receive(:parent=).with(c.current_scope_object) # factory.project.should_receive(:parent=).with(c.current_scope_object)
65
- c.send(scope_name, :bar) {} # c.project(:bar) {}
66
- end # end
67
- end #
31
+ parent_scope_variants = scopes[parent_scope_name]
32
+
33
+ context "under #{parent_scope_name} #{parent_scope_variants.inspect}" do
34
+ it { should enclose_scope(scope_name).under(parent_scope_variants) }
35
+
36
+ it "creates a #{scope_name} under #{parent_scope_name} and set it as current scope object" do
37
+ within_parent_dsl(parent_scope_name) do |c|
38
+ stub_find_or_create_scope_object(c, scope_name, :bar)
39
+ c.send(scope_name, :bar) do
40
+ expect(c.current_scope_object).to eq(factory.send(scope_name))
41
+ end
42
+ end
43
+ end
44
+
45
+ it "does not leak #{scope_name} as current scope object" do
46
+ within_parent_dsl(parent_scope_name) do |c|
47
+ stub_find_or_create_scope_object(c, scope_name, :bar)
48
+ c.send(scope_name, :bar) do
49
+ expect(c.current_scope_object).to eq(factory.send(scope_name))
50
+ end
51
+ expect(c.current_scope_object).not_to eq(factory.send(scope_name))
52
+ end
53
+ end
54
+
55
+ it "adds a #{scope_name} to the #{parent_scope_name}'s #{scope_name}s collection" do
56
+ within_parent_dsl(parent_scope_name) do |c|
57
+ stub_find_or_create_scope_object(c, scope_name, :bar)
58
+ c.current_scope_object.should_receive("append_#{scope_name}").
59
+ with(factory.send(scope_name))
60
+ c.send(scope_name, :bar) {}
61
+ end
62
+ end
63
+
64
+ it "sets #{scope_name}'s parent to the #{parent_scope_name} scope object" do
65
+ within_parent_dsl(parent_scope_name) do |c|
66
+ stub_find_or_create_scope_object(c, scope_name, :bar)
67
+ factory.send(scope_name).should_receive(:parent=).with(c.current_scope_object)
68
+ c.send(scope_name, :bar) {}
69
+ end
70
+ end
71
+ end
68
72
  end
69
73
  end
70
74
 
@@ -72,11 +76,11 @@ describe "DSL" do
72
76
  it_behaves_like "a scoped construct", attribute_name, parent_scope_names, false
73
77
 
74
78
  Array(parent_scope_names).each do |parent_scope_name|
75
- it "calls #{parent_scope_method} on current #{parent_scope_name}" do # it "calls default_location= on current server" do
76
- dsl(scopes[parent_scope_name], factory.create(parent_scope_name, :foo)) do |c| # dsl([:config, :project, :environment, :server], factory.create(:server, :foo)) do |c|
77
- factory.send(parent_scope_name).should_receive(parent_scope_method).with(example_value) # factory.server.should_receive(:default_location=).with('/var/app/')
78
- c.send(attribute_name, example_value) # c.location "/var/app"
79
- end # end
79
+ it "calls #{parent_scope_method} on current #{parent_scope_name}" do
80
+ within_parent_dsl(parent_scope_name) do |c|
81
+ factory.send(parent_scope_name).should_receive(parent_scope_method).with(example_value)
82
+ c.send(attribute_name, example_value)
83
+ end
80
84
  end
81
85
  end
82
86
  end
@@ -86,10 +90,10 @@ describe "DSL" do
86
90
  end
87
91
 
88
92
  describe "#default_server_config" do
89
- it_behaves_like "a scoped construct", :default_server_config, [:config, :project, :environment]
93
+ it_behaves_like "a scoped construct", :default_server_config, [:config, :project, :environment, :group]
90
94
 
91
95
  it "stores a block" do
92
- dsl(scopes[:config], factory.create(:config)) do |c|
96
+ within_parent_dsl(:config) do |c|
93
97
  cfg = proc { any_method_call_here }
94
98
  factory.config.should_receive(:default_server_config=).with(cfg)
95
99
  c.default_server_config(&cfg)
@@ -101,7 +105,7 @@ describe "DSL" do
101
105
  it_behaves_like "a scoped construct", :shared_server_config, :config
102
106
 
103
107
  it "stores a block" do
104
- dsl(scopes[:config], factory.create(:config)) do |c|
108
+ within_parent_dsl(:config) do |c|
105
109
  cfg = proc { any_method_call_here }
106
110
  c.shared_server_config(:foo, &cfg)
107
111
  expect(c.shared_server_configs[:foo]).to eq(cfg)
@@ -111,10 +115,10 @@ describe "DSL" do
111
115
 
112
116
  describe "#include_shared_server_config" do
113
117
  it "executes the block on dsl object in server scope for given shared config names" do
114
- dsl(scopes[:server], factory.create(:server)) do |c|
118
+ within_parent_dsl(:server) do |c|
115
119
  c.stub(:shared_server_configs => { :foo => proc { call_from_foo }, :bar => proc { call_from_bar } })
116
- c.should_receive(:call_from_foo)
117
- c.should_receive(:call_from_bar)
120
+ c.should_receive(:call_from_foo).once
121
+ c.should_receive(:call_from_bar).once
118
122
  c.include_shared_server_config(:foo, :bar)
119
123
  end
120
124
  end
@@ -122,7 +126,7 @@ describe "DSL" do
122
126
  context "when the argument is hash where shared config names are keys" do
123
127
  context "when hash values are arrays" do
124
128
  it "includes config corresponding to hash key and passes exploded arguments" do
125
- dsl(scopes[:server], factory.create(:server)) do |c|
129
+ within_parent_dsl(:server) do |c|
126
130
  c.stub(:shared_server_configs => { :foo => proc { |a, b| any_method_call_here(a, b) } })
127
131
  c.should_receive(:any_method_call_here).with(321, 322)
128
132
  c.include_shared_server_config(:foo => [321, 322])
@@ -132,7 +136,7 @@ describe "DSL" do
132
136
 
133
137
  context "when hash values are single values" do
134
138
  it "includes config corresponding to hash key and passes the argument" do
135
- dsl(scopes[:server], factory.create(:server)) do |c|
139
+ within_parent_dsl(:server) do |c|
136
140
  c.stub(:shared_server_configs => { :foo => proc { |qux| any_method_call_here(qux) } })
137
141
  c.should_receive(:any_method_call_here).with(321)
138
142
  c.include_shared_server_config(:foo => 321)
@@ -143,7 +147,7 @@ describe "DSL" do
143
147
 
144
148
  context "whne there are symbol arguments (names of shared configs) and a hash" do
145
149
  it "includes config corresponding to symbol arguments and hash keys" do
146
- dsl(scopes[:server], factory.create(:server)) do |c|
150
+ within_parent_dsl(:server) do |c|
147
151
  c.stub(:shared_server_configs => { :foo => proc { call_from_foo }, :bar => proc { |qux| call_from_bar(qux) } })
148
152
  c.should_receive(:call_from_foo)
149
153
  c.should_receive(:call_from_bar).with(123)
@@ -153,7 +157,7 @@ describe "DSL" do
153
157
  end
154
158
 
155
159
  it "raises ConfigError if non-existent config included" do
156
- dsl(scopes[:server], factory.create(:server)) do |c|
160
+ within_parent_dsl(:server) do |c|
157
161
  expect { c.include_shared_server_config(:foo) }.to raise_error(Taketo::DSL::ConfigError, "Shared server config 'foo' is not defined!")
158
162
  end
159
163
  end
@@ -167,25 +171,25 @@ describe "DSL" do
167
171
  it_behaves_like "a scope", :environment, :project
168
172
  end
169
173
 
174
+ describe "#group" do
175
+ it_behaves_like "a scope", :group, [:project, :environment, :config]
176
+ end
177
+
170
178
  describe "#server" do
171
- it_behaves_like "a scope", :server, [:environment, :config, :project]
179
+ it_behaves_like "a scope", :server, [:environment, :config, :project, :group]
172
180
 
173
181
  it "evaluates default_server_config" do
174
- dsl(scopes[:environment], factory.create(:environment, :foo)) do |c|
182
+ within_parent_dsl(:environment) do |c|
175
183
  stub_find_or_create_scope_object(c, :server, :bar)
176
-
177
184
  default_server_config = proc { some_setup }
178
185
  factory.server.stub(:default_server_config => default_server_config)
179
-
180
186
  c.should_receive(:some_setup)
181
-
182
- c.server(:bar) do
183
- end
187
+ c.server(:bar) {}
184
188
  end
185
189
  end
186
190
 
187
191
  it "has name optional" do
188
- dsl(scopes[:environment], factory.create(:environment, :foo)) do |c|
192
+ within_parent_dsl(:environment) do |c|
189
193
  stub_find_or_create_scope_object(c, :server, :default)
190
194
  c.server do
191
195
  expect(c.current_scope_object.name).to eq(:default)
@@ -246,11 +250,11 @@ describe "DSL" do
246
250
  end
247
251
 
248
252
  it "corresponds to current scope" do
249
- dsl(:project, factory.create_project(:foo)) do |c|
253
+ within_parent_dsl(:project) do |c|
250
254
  expect(c.current_scope_object).to eq(factory.project)
251
255
  end
252
256
 
253
- dsl(:server, factory.create_server(:foo)) do |c|
257
+ within_parent_dsl(:server) do |c|
254
258
  expect(c.current_scope_object).to eq(factory.server)
255
259
  end
256
260
  end
@@ -282,9 +286,17 @@ describe "DSL" do
282
286
  it "raises meaningful error if config parse failed"
283
287
  end
284
288
 
285
- def stub_find_or_create_scope_object(scope_object, scope, name)
286
- scope_object.current_scope_object.should_receive(:find).and_yield.and_return(factory.create(scope, name))
287
- factory.should_receive(:create).with(scope, name)
289
+ def stub_find_or_create_scope_object(dsl_object, scope, name)
290
+ dsl_object.current_scope_object.stub(:find).with(scope, name).and_yield.and_return(factory.create(scope, name))
288
291
  end
292
+
293
+ def within_parent_dsl(parent_scope, &block)
294
+ scopes[parent_scope].each do |parent_scope_variant|
295
+ dsl(parent_scope_variant, factory.create(parent_scope)) do |c|
296
+ block.call(c)
297
+ end
298
+ end
299
+ end
300
+
289
301
  end
290
302
 
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'taketo/group_list_visitor'
3
+
4
+ include Taketo
5
+
6
+ describe "GroupListVisitor" do
7
+ subject(:group_list) { GroupListVisitor.new }
8
+
9
+ describe "#result" do
10
+ it "outputs list of qualified server names" do
11
+ server1 = stub(:Server, :path => "foo")
12
+ server2 = stub(:Server, :path => "bar")
13
+ group_list.visit_server(server1)
14
+ group_list.visit_server(server2)
15
+ group_list.result.should == "foo\nbar"
16
+ end
17
+ end
18
+ end
19
+
20
+
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+ require 'support/helpers/construct_spec_helper'
3
+ require 'taketo/group_resolver'
4
+
5
+ include Taketo
6
+
7
+ describe "GroupResolver" do
8
+ include ConstructsFixtures
9
+
10
+ let(:server1) { s = server(:s1); s.global_alias = :the_alias; s }
11
+ let(:environment1) { environment(:bar, :servers => server1) }
12
+ let(:project1) { project(:foo, :environments => environment1) }
13
+
14
+ let(:server2) { server(:s2) }
15
+ let(:environment2) { environment(:qux, :servers => server2) }
16
+ let(:project2) { project(:baz, :environments => environment2) }
17
+
18
+ let(:server3) { server(:s3) }
19
+ let(:server4) { server(:s4) }
20
+ let(:environment3) { environment(:corge, :servers => [server3, server4]) }
21
+ let(:project3) { project(:quux, :environments => environment3) }
22
+
23
+ let(:server5) { server(:s5) }
24
+ let(:server6) { server(:s6) }
25
+ let(:environment4) { environment(:garply, :servers => [server5, server6]) }
26
+ let(:environment5) { environment(:waldo, :servers => server(:s7)) }
27
+ let(:project4) { project(:grault, :environments => [environment4, environment5]) }
28
+
29
+ let(:config) { create_config(:projects => [project1, project2, project3, project4]) }
30
+
31
+ describe "#resolve" do
32
+ it "does not resolve to server" do
33
+ expect{ resolver(config, "foo:bar:s1").resolve }.to raise_error(Taketo::NonExistentDestinationError)
34
+ end
35
+
36
+ it "returns environment when path has 2 segments and is correct" do
37
+ expect(resolver(config, "foo:bar").resolve).to eq(environment1)
38
+ end
39
+
40
+ it "returns project when path has 1 segment and is correct" do
41
+ expect(resolver(config, "foo").resolve).to eq(project1)
42
+ end
43
+
44
+ it "returns the config if path has is empty and there's no default destination" do
45
+ expect(resolver(config, "").resolve).to eq(config)
46
+ end
47
+
48
+ it "raises NonExistentDestinationError when path is not correct" do
49
+ expect { resolver(config, "i").resolve }.to raise_error(NonExistentDestinationError)
50
+ end
51
+ end
52
+
53
+ def resolver(*args)
54
+ GroupResolver.new(*args)
55
+ end
56
+
57
+ end
58
+
59
+
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
  require 'support/helpers/construct_spec_helper'
3
- require 'taketo/destination_resolver'
3
+ require 'taketo/server_resolver'
4
4
 
5
5
  include Taketo
6
6
 
7
- describe "DestinationResolver" do
7
+ describe "ServerResolver" do
8
8
  include ConstructsFixtures
9
9
 
10
10
  let(:server1) { s = server(:s1); s.global_alias = :the_alias; s }
@@ -145,34 +145,8 @@ describe "DestinationResolver" do
145
145
  end
146
146
  end
147
147
 
148
- describe "#get_node" do
149
- it "returns server when path has 3 segments and is correct" do
150
- expect(resolver(config, "foo:bar:s1").get_node).to eq(server1)
151
- end
152
-
153
- it "returns environment when path has 2 segments and is correct" do
154
- expect(resolver(config, "foo:bar").get_node).to eq(environment1)
155
- end
156
-
157
- it "returns project when path has 1 segment and is correct" do
158
- expect(resolver(config, "foo").get_node).to eq(project1)
159
- end
160
-
161
- it "returns the config if path has is empty and there's no default destination" do
162
- expect(resolver(config, "").get_node).to eq(config)
163
- end
164
-
165
- it "resolves to server by global server alias" do
166
- expect(resolver(config, "the_alias").get_node).to eq(server1)
167
- end
168
-
169
- it "raises NonExistentDestinationError when path is not correct" do
170
- expect { resolver(config, "i").get_node }.to raise_error(NonExistentDestinationError)
171
- end
172
- end
173
-
174
148
  def resolver(*args)
175
- DestinationResolver.new(*args)
149
+ ServerResolver.new(*args)
176
150
  end
177
151
 
178
152
  end
@@ -15,6 +15,15 @@ shared_examples "a construct with nodes" do |name_plural, name_singular|
15
15
  end # end
16
16
  end
17
17
 
18
+ shared_examples "a node with servers" do
19
+ it_behaves_like "a construct with nodes", :servers, :server
20
+
21
+ specify "#has_servers? should perform deep search on child nodes" do
22
+ subject.should_receive(:has_deeply_nested_nodes?).with(:servers)
23
+ subject.has_servers?
24
+ end
25
+ end
26
+
18
27
  module ConstructsFixtures
19
28
  include Taketo::Constructs
20
29
 
@@ -1,6 +1,6 @@
1
1
  module DSLSpec
2
2
  class TestConstructsFactory
3
- attr_reader :config, :project, :environment, :server, :command
3
+ attr_reader :config, :project, :environment, :server, :group, :command
4
4
 
5
5
  def create(type, *args)
6
6
  send("create_#{type}", *args)
@@ -22,6 +22,10 @@ module DSLSpec
22
22
  @server ||= RSpec::Mocks::Mock.new(:Server, :name => name, :default_server_config => proc {}).as_null_object
23
23
  end
24
24
 
25
+ def create_group(name = :foo)
26
+ @group ||= RSpec::Mocks::Mock.new(:Group, :name => name, :default_server_config => proc {}).as_null_object
27
+ end
28
+
25
29
  def create_command(name = :the_cmd)
26
30
  @command ||= RSpec::Mocks::Mock.new(:Command, :name => name, :default_server_config => proc {}).as_null_object
27
31
  end
@@ -37,7 +41,7 @@ module DSLSpec
37
41
  end
38
42
  end
39
43
 
40
- def dsl(scope = [:config], scope_object = nil)
44
+ def dsl(scope = scopes[:config], scope_object = nil, &block)
41
45
  context = DSL.new(factory)
42
46
 
43
47
  def context.set_scope(s, obj)
@@ -46,17 +50,35 @@ module DSLSpec
46
50
  end
47
51
 
48
52
  context.set_scope(scope, scope_object || factory.create_config)
49
-
50
- yield context
53
+ block.call(context)
51
54
  end
52
55
 
53
56
  def scopes
54
57
  scopes_hash = {
55
- :config => [:config],
56
- :project => [:config, :project],
57
- :environment => [:config, :project, :environment],
58
- :server => [:config, :project, :environment, :server],
59
- :command => [:config, :project, :environment, :server, :command]
58
+ :config => [[:config]],
59
+ :project => [[:config, :project]],
60
+ :environment => [[:config, :project, :environment]],
61
+ :group => [
62
+ [:config, :group],
63
+ [:config, :project, :group],
64
+ [:config, :project, :environment, :group]
65
+ ],
66
+ :server => [
67
+ # [:config, :server],
68
+ # [:config, :group, :server],
69
+ # [:config, :project, :server],
70
+ # [:config, :project, :group, :server],
71
+ # [:config, :project, :environment, :server],
72
+ [:config, :project, :environment, :group, :server]
73
+ ],
74
+ :command => [
75
+ [:config, :server, :command],
76
+ [:config, :group, :server, :command],
77
+ [:config, :project, :server, :command],
78
+ [:config, :project, :group, :server, :command],
79
+ [:config, :project, :environment, :server, :command],
80
+ [:config, :project, :environment, :group, :server, :command]
81
+ ]
60
82
  }
61
83
 
62
84
  def scopes_hash.except(*keys)