taketo 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/README.md +20 -7
- data/VERSION +1 -1
- data/bin/taketo +30 -31
- data/features/config.feature +33 -3
- data/features/config_validation.feature +29 -4
- data/features/connect_to_server.feature +2 -1
- data/features/error_handling.feature +1 -0
- data/features/help.feature +5 -3
- data/features/support/env.rb +2 -0
- data/lib/taketo/associated_nodes.rb +90 -0
- data/lib/taketo/commands/ssh_command.rb +0 -4
- data/lib/taketo/config_printer_visitor.rb +68 -0
- data/lib/taketo/config_traverser.rb +55 -0
- data/lib/taketo/config_validator.rb +33 -34
- data/lib/taketo/config_visitor.rb +29 -0
- data/lib/taketo/constructs/base_construct.rb +9 -54
- data/lib/taketo/constructs/command.rb +9 -1
- data/lib/taketo/constructs/environment.rb +11 -1
- data/lib/taketo/constructs/project.rb +5 -0
- data/lib/taketo/constructs/server.rb +7 -4
- data/lib/taketo/dsl.rb +13 -2
- data/lib/taketo/support/named_nodes_collection.rb +10 -0
- data/lib/taketo/support.rb +0 -1
- data/lib/taketo.rb +2 -1
- data/spec/integration/dsl_integration_spec.rb +1 -1
- data/spec/lib/taketo/associated_nodes_spec.rb +101 -0
- data/spec/lib/taketo/commands/ssh_command_spec.rb +5 -15
- data/spec/lib/taketo/config_printer_visitor_spec.rb +112 -0
- data/spec/lib/taketo/config_traverser_spec.rb +63 -0
- data/spec/lib/taketo/config_validator_spec.rb +53 -39
- data/spec/lib/taketo/config_visitor_spec.rb +51 -0
- data/spec/lib/taketo/constructs/base_construct_spec.rb +7 -70
- data/spec/lib/taketo/constructs/command_spec.rb +20 -8
- data/spec/lib/taketo/constructs/config_spec.rb +2 -6
- data/spec/lib/taketo/constructs/environment_spec.rb +12 -7
- data/spec/lib/taketo/constructs/project_spec.rb +10 -4
- data/spec/lib/taketo/constructs/server_spec.rb +25 -16
- data/spec/lib/taketo/constructs_factory_spec.rb +12 -12
- data/spec/lib/taketo/destination_resolver_spec.rb +32 -32
- data/spec/lib/taketo/dsl_spec.rb +115 -98
- data/spec/lib/taketo/support/named_nodes_collection_spec.rb +49 -21
- data/spec/support/helpers/construct_spec_helper.rb +5 -5
- data/spec/support/matchers/be_appropriate_construct_matcher.rb +9 -1
- data/spec/support/matchers/have_accessor_matcher.rb +6 -3
- metadata +18 -7
- data/lib/taketo/config_printer.rb +0 -84
- data/lib/taketo/support/eval_delegator.rb +0 -25
- data/spec/lib/taketo/config_printer_spec.rb +0 -116
- data/spec/lib/taketo/support/eval_delegator_spec.rb +0 -43
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'taketo/constructs'
|
2
|
+
|
3
|
+
module Taketo
|
4
|
+
def self.downcased_construct_class_name(klass)
|
5
|
+
klass.name.gsub("Taketo::Constructs::", "").gsub(/[A-Z][^A-Z]*/) { |s| s.gsub("::", "").downcase + "_" }.chop
|
6
|
+
end
|
7
|
+
|
8
|
+
class ConfigVisitor
|
9
|
+
include Taketo::Constructs
|
10
|
+
|
11
|
+
def self.visit(*klasses, &block)
|
12
|
+
klasses.each do |klass|
|
13
|
+
define_method(:"visit_#{Taketo.downcased_construct_class_name(klass)}", block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def visit(obj)
|
18
|
+
obj.class.ancestors.each do |ancestor|
|
19
|
+
next unless ancestor.name # skip anonymous classes
|
20
|
+
method_name = :"visit_#{Taketo.downcased_construct_class_name(ancestor)}"
|
21
|
+
next unless respond_to?(method_name)
|
22
|
+
return send(method_name, obj)
|
23
|
+
end
|
24
|
+
|
25
|
+
raise "Don't know how to visit #{obj.class}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -1,72 +1,27 @@
|
|
1
1
|
require 'taketo/support'
|
2
|
+
require 'taketo/associated_nodes'
|
2
3
|
|
3
4
|
module Taketo
|
4
|
-
class NodesNotDefinedError < StandardError; end
|
5
|
-
|
6
5
|
module Constructs
|
7
6
|
class BaseConstruct
|
8
|
-
attr_reader :name
|
9
|
-
|
10
|
-
##
|
11
|
-
# Adds nodes collections to the construct
|
12
|
-
#
|
13
|
-
# Example:
|
14
|
-
#
|
15
|
-
# class Bar < BaseConstruct
|
16
|
-
# has_nodes :foos, :foo
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# bar = Bar.new
|
20
|
-
# bar.foos # => foos collection
|
21
|
-
# bar.append_foo(foo) # adds node the collection
|
22
|
-
# bar.find_foo(:foo_name) # find foo in foos collection by name
|
23
|
-
#
|
24
|
-
def self.has_nodes(name_plural, name_singular)
|
25
|
-
self.node_types << name_plural
|
26
|
-
|
27
|
-
define_method "append_#{name_singular}" do |object|
|
28
|
-
nodes(name_plural) << object
|
29
|
-
end
|
30
7
|
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
define_method name_plural do
|
36
|
-
nodes(name_plural)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.node_types
|
41
|
-
@node_types ||= []
|
42
|
-
end
|
8
|
+
include AssociatedNodes
|
9
|
+
attr_reader :name
|
43
10
|
|
44
11
|
def initialize(name)
|
12
|
+
super
|
45
13
|
@name = name
|
46
|
-
@nodes = {}
|
47
|
-
end
|
48
|
-
|
49
|
-
def find(singular_node_name, name)
|
50
|
-
send("find_#{singular_node_name}", name) or
|
51
|
-
if block_given?
|
52
|
-
yield
|
53
|
-
else
|
54
|
-
raise KeyError, "#{singular_node_name} #{name} not found for #{node_type} #{self.name}"
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def nodes(name_plural)
|
59
|
-
unless self.class.node_types.include?(name_plural)
|
60
|
-
raise NodesNotDefinedError, "#{name_plural} not defined for #{node_type}"
|
61
|
-
end
|
62
|
-
@nodes[name_plural] ||= Taketo::Support::NamedNodesCollection.new
|
63
14
|
end
|
64
15
|
|
65
16
|
def node_type
|
66
17
|
demodulized = self.class.name.gsub(/.*::/, '')
|
67
18
|
demodulized.gsub(/([a-z])([A-Z])/, '\\1_\\2').downcase.to_sym
|
68
19
|
end
|
69
|
-
|
20
|
+
|
21
|
+
def qualified_name
|
22
|
+
"#{node_type} #{self.name}"
|
23
|
+
end
|
24
|
+
|
70
25
|
end
|
71
26
|
end
|
72
27
|
end
|
@@ -7,7 +7,15 @@ module Taketo
|
|
7
7
|
include Shellwords
|
8
8
|
|
9
9
|
attr_accessor :command, :description
|
10
|
-
|
10
|
+
|
11
|
+
def self.default
|
12
|
+
new(:default).tap { |cmd| cmd.command = "bash" }
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.explicit_command(command_string)
|
16
|
+
new(:explicit_command).tap { |cmd| cmd.command = command_string }
|
17
|
+
end
|
18
|
+
|
11
19
|
def render(server, options = {})
|
12
20
|
%Q[#{location(server, options)} #{environment_variables(server)} #{command}].strip.squeeze(" ")
|
13
21
|
end
|
@@ -6,9 +6,19 @@ module Taketo
|
|
6
6
|
class Environment < BaseConstruct
|
7
7
|
has_nodes :servers, :server
|
8
8
|
|
9
|
+
attr_accessor :project
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
super(name)
|
13
|
+
end
|
14
|
+
|
15
|
+
def project_name
|
16
|
+
@project.name if defined? @project
|
17
|
+
end
|
18
|
+
|
9
19
|
def append_server(server)
|
10
20
|
server.environment = self
|
11
|
-
|
21
|
+
super
|
12
22
|
end
|
13
23
|
end
|
14
24
|
end
|
@@ -1,14 +1,13 @@
|
|
1
1
|
require 'taketo/constructs/base_construct'
|
2
|
+
require 'taketo/constructs/command'
|
2
3
|
require 'taketo/support'
|
3
4
|
|
4
5
|
module Taketo
|
5
|
-
class CommandNotFoundError < StandardError; end
|
6
|
-
|
7
6
|
module Constructs
|
8
7
|
class Server < BaseConstruct
|
9
8
|
attr_reader :environment_variables
|
10
|
-
attr_accessor :host, :port, :username, :default_location, :environment, :global_alias, :identity_file
|
11
|
-
|
9
|
+
attr_accessor :host, :port, :username, :default_location, :default_command, :environment, :global_alias, :identity_file
|
10
|
+
|
12
11
|
has_nodes :commands, :command
|
13
12
|
|
14
13
|
def initialize(name)
|
@@ -24,6 +23,10 @@ module Taketo
|
|
24
23
|
env(:RAILS_ENV => environment.name.to_s)
|
25
24
|
@environment = environment
|
26
25
|
end
|
26
|
+
|
27
|
+
def default_command
|
28
|
+
defined?(@default_command) ? @default_command : Command.default
|
29
|
+
end
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
data/lib/taketo/dsl.rb
CHANGED
@@ -74,9 +74,20 @@ module Taketo
|
|
74
74
|
@shared_server_configs.store(name.to_sym, blk)
|
75
75
|
end
|
76
76
|
|
77
|
-
define_method_in_scope(:include_shared_server_config, :server) do
|
78
|
-
|
77
|
+
define_method_in_scope(:include_shared_server_config, :server) do |*args|
|
78
|
+
if args.first.is_a?(Hash)
|
79
|
+
configs_and_arguments = args.shift
|
80
|
+
configs_and_arguments.each do |config_name, arguments|
|
81
|
+
instance_exec(*arguments, &shared_server_configs[config_name])
|
82
|
+
end
|
83
|
+
else
|
84
|
+
args.each do |config_name|
|
85
|
+
instance_exec(&shared_server_configs[config_name])
|
86
|
+
end
|
87
|
+
end
|
79
88
|
end
|
89
|
+
alias :include_shared_server_configs :include_shared_server_config
|
90
|
+
|
80
91
|
|
81
92
|
private
|
82
93
|
|
@@ -15,6 +15,7 @@ module Taketo
|
|
15
15
|
|
16
16
|
def push(node)
|
17
17
|
@nodes << node unless find_by_name(node.name)
|
18
|
+
self
|
18
19
|
end
|
19
20
|
alias :<< :push
|
20
21
|
|
@@ -29,6 +30,15 @@ module Taketo
|
|
29
30
|
def find_by_name(name)
|
30
31
|
@nodes.detect { |n| n.name == name }
|
31
32
|
end
|
33
|
+
|
34
|
+
def ==(other)
|
35
|
+
return true if other.equal?(self)
|
36
|
+
@nodes == other.is_a?(NamedNodesCollection) ? other.nodes : other
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
attr_reader :nodes
|
32
42
|
end
|
33
43
|
end
|
34
44
|
end
|
data/lib/taketo/support.rb
CHANGED
data/lib/taketo.rb
CHANGED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'taketo/associated_nodes'
|
3
|
+
|
4
|
+
include Taketo
|
5
|
+
|
6
|
+
class TestAssociatedNodes
|
7
|
+
include AssociatedNodes
|
8
|
+
|
9
|
+
has_nodes :foos, :foo
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "AssociatedNodes" do
|
13
|
+
subject(:construct) { TestAssociatedNodes.new(:my_node) }
|
14
|
+
let(:foo) { stub(:FooNode, :name => :bar) }
|
15
|
+
|
16
|
+
describe ".has_nodes" do
|
17
|
+
it "adds node type to class's node_types" do
|
18
|
+
expect(TestAssociatedNodes.node_types).to include(:foos)
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "#foos returns mutable foos collection" do
|
22
|
+
construct.nodes(:foos) << foo
|
23
|
+
expect(construct.foos).to eq([foo])
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "#append_foo adds a foo to nested foos collection" do
|
27
|
+
construct.nodes(:foos) << foo
|
28
|
+
expect(construct.nodes(:foos)).to include(foo)
|
29
|
+
end
|
30
|
+
|
31
|
+
specify "#find_foo returns node with corresponding name" do
|
32
|
+
construct.nodes(:foos) << foo
|
33
|
+
expect(construct.find_foo(:bar)).to eq(foo)
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#has_foos?" do
|
37
|
+
context "when there are no foos" do
|
38
|
+
it "returns false" do
|
39
|
+
expect(construct).not_to have_foos
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when there are some foos" do
|
44
|
+
it "returns true" do
|
45
|
+
construct.nodes(:foos) << foo
|
46
|
+
expect(construct).to have_foos
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#find" do
|
53
|
+
context "when node is present" do
|
54
|
+
it "returns node object with corresponding name" do
|
55
|
+
construct.nodes(:foos) << foo
|
56
|
+
expect(construct.find(:foo, :bar)).to eq(foo)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when node is absent" do
|
61
|
+
it "yields if block given" do
|
62
|
+
expect { |b| construct.find(:foo, :bar, &b) }.to yield_control
|
63
|
+
end
|
64
|
+
|
65
|
+
it "raises KeyError if no block given" do
|
66
|
+
expect { construct.find(:foo, :bar) }.to raise_error(KeyError)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "#nodes" do
|
72
|
+
it "returns nodes collection by plural name" do
|
73
|
+
construct.nodes(:foos) << foo
|
74
|
+
expect(construct.nodes(:foos)).to eq([foo])
|
75
|
+
end
|
76
|
+
|
77
|
+
it "raises NodesNotDefinedError if non-specified node requested" do
|
78
|
+
expect { construct.nodes(:bars) }.to raise_error(NodesNotDefinedError, /bars/)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#has_nodes?" do
|
83
|
+
context "when nodes are present" do
|
84
|
+
it "returns true" do
|
85
|
+
construct.nodes(:foos) << foo
|
86
|
+
expect(construct).to have_nodes(:foos)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when nodes are absent" do
|
91
|
+
it "returns false" do
|
92
|
+
expect(construct).not_to have_nodes(:foos)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "raises if node can not have children of specified type" do
|
97
|
+
expect { construct.has_nodes?(:quack) }.to raise_error NodesNotDefinedError
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'taketo/commands/ssh_command'
|
3
3
|
|
4
4
|
include Taketo::Commands
|
5
5
|
|
6
6
|
describe "SSH Command" do
|
7
|
-
let(:environment) { stub(:Environment, :name => :staging) }
|
8
7
|
let(:server) do
|
9
8
|
stub(:Server, :name => :s1,
|
10
9
|
:host => "1.2.3.4",
|
@@ -12,27 +11,18 @@ describe "SSH Command" do
|
|
12
11
|
:username => "deployer",
|
13
12
|
:default_location => "/var/app",
|
14
13
|
:identity_file => "/home/gor/.ssh/qqq",
|
15
|
-
:environment => environment,
|
16
14
|
:environment_variables => {})
|
17
15
|
end
|
18
|
-
let(:command) { mock(:Command, :render => "the_command") }
|
19
16
|
|
20
|
-
|
17
|
+
subject(:ssh_command) { SSHCommand.new(server) }
|
21
18
|
|
22
|
-
it "
|
19
|
+
it "composes command based on provided server object" do
|
23
20
|
ssh_command.render("foobar").should == %q[ssh -t -p 22 -i /home/gor/.ssh/qqq deployer@1.2.3.4 "foobar"]
|
24
21
|
end
|
25
22
|
|
26
|
-
it "
|
27
|
-
server.stub(:port => nil)
|
28
|
-
server.stub(:username => nil)
|
29
|
-
server.stub(:identity_file => nil)
|
23
|
+
it "ignores absent parts if they are not required" do
|
24
|
+
server.stub(:port => nil, :username => nil, :identity_file => nil)
|
30
25
|
ssh_command.render("foobar").should == %q[ssh -t 1.2.3.4 "foobar"]
|
31
26
|
end
|
32
|
-
|
33
|
-
it "should require host" do
|
34
|
-
server.stub(:host => nil)
|
35
|
-
expect { ssh_command.render("bash") }.to raise_error ArgumentError, /host/
|
36
|
-
end
|
37
27
|
end
|
38
28
|
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'taketo/config_printer_visitor'
|
3
|
+
|
4
|
+
include Taketo
|
5
|
+
|
6
|
+
describe "ConfigPrinterVisitor" do
|
7
|
+
subject(:printer) { ConfigPrinterVisitor.new }
|
8
|
+
|
9
|
+
describe "#visit_command" do
|
10
|
+
let(:command) { stub(:Command, :name => :foo, :description => nil) }
|
11
|
+
|
12
|
+
it "renders command name" do
|
13
|
+
printer.visit_command(command)
|
14
|
+
expect(printer.result).to eq("foo")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "renders description if available" do
|
18
|
+
command.stub(:description => "The description")
|
19
|
+
printer.visit_command(command)
|
20
|
+
expect(printer.result).to eq("foo - The description")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#visit_server" do
|
25
|
+
let(:server) do
|
26
|
+
stub(:Server,
|
27
|
+
:name => :sponge,
|
28
|
+
:host => "1.2.3.4",
|
29
|
+
:port => 8000,
|
30
|
+
:username => "bob",
|
31
|
+
:default_location => "/var/app",
|
32
|
+
:environment_variables => { :FOO => "bar", :BOO => "baz" })
|
33
|
+
end
|
34
|
+
|
35
|
+
it "renders available server info" do
|
36
|
+
server.stub(:has_commands? => true)
|
37
|
+
printer.visit_server(server)
|
38
|
+
expect(printer.result).to match(
|
39
|
+
%r[Server: sponge
|
40
|
+
Host: 1\.2\.3\.4
|
41
|
+
Port: 8000
|
42
|
+
User: bob
|
43
|
+
Default location: /var/app
|
44
|
+
Environment: (FOO=bar BOO=baz|BOO=baz FOO=bar)])
|
45
|
+
end
|
46
|
+
|
47
|
+
it "renders appropriate message if there are no commands" do
|
48
|
+
server.stub(:has_commands? => false)
|
49
|
+
printer.visit_server(server)
|
50
|
+
expect(printer.result).to include("(No commands)")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#visit_environment" do
|
55
|
+
let(:environment) { stub(:Environment, :name => :foo) }
|
56
|
+
|
57
|
+
it "renders environment info" do
|
58
|
+
environment.stub(:has_servers? => true)
|
59
|
+
printer.visit_environment(environment)
|
60
|
+
expect(printer.result).to eq("Environment: foo")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "renders appropriate message if there are no servers" do
|
64
|
+
environment.stub(:has_servers? => false)
|
65
|
+
printer.visit_environment(environment)
|
66
|
+
expect(printer.result).to include("Environment: foo\n (No servers)")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#visit_project" do
|
71
|
+
let(:project) { stub(:Project, :name => :quux) }
|
72
|
+
|
73
|
+
it "renders project info" do
|
74
|
+
project.stub(:has_environments? => true)
|
75
|
+
printer.visit_project(project)
|
76
|
+
expect(printer.result).to eq("\nProject: quux")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "renders appropriate message if there are no environments for project" do
|
80
|
+
project.stub(:has_environments? => false)
|
81
|
+
printer.visit_project(project)
|
82
|
+
expect(printer.result).to eq("\nProject: quux\n (No environments)")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#visit_config" do
|
87
|
+
let(:config) { stub(:Config, :default_destination => "hello:bye") }
|
88
|
+
|
89
|
+
it "renders default destination and all projects" do
|
90
|
+
config.stub(:has_projects? => true)
|
91
|
+
printer.visit_config(config)
|
92
|
+
expect(printer.result).to eq("Default destination: hello:bye")
|
93
|
+
end
|
94
|
+
|
95
|
+
it "renders appropriate message if there are no projects" do
|
96
|
+
config.stub(:has_projects? => false)
|
97
|
+
printer.visit_config(config)
|
98
|
+
expect(printer.result).to eq("There are no projects yet...")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "indents relatively" do
|
103
|
+
config = stub(:Config, :default_destination => "hello:bye", :has_projects? => true)
|
104
|
+
project = stub(:Project, :name => :quux, :has_environments? => true)
|
105
|
+
environment = stub(:Environment, :name => :foo, :has_servers? => false)
|
106
|
+
printer.visit_config(config)
|
107
|
+
printer.visit_project(project)
|
108
|
+
printer.visit_environment(environment)
|
109
|
+
expect(printer.result).to eq("Default destination: hello:bye\n\nProject: quux\n Environment: foo\n (No servers)")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'taketo/config_traverser'
|
3
|
+
|
4
|
+
# config 1
|
5
|
+
# / \
|
6
|
+
# project 1 2
|
7
|
+
# / \
|
8
|
+
# environment 1 2
|
9
|
+
# /|\
|
10
|
+
# server 1 2 3
|
11
|
+
|
12
|
+
describe Taketo::ConfigTraverser do
|
13
|
+
let(:server_1) { stub(:Server1, :node_type => :server, :name => :server_1).as_null_object }
|
14
|
+
let(:server_2) { stub(:Server2, :node_type => :server, :name => :server_2).as_null_object }
|
15
|
+
let(:server_3) { stub(:Server3, :node_type => :server, :name => :server_3).as_null_object }
|
16
|
+
|
17
|
+
let(:environment_1) { stub(:Environment1, :node_type => :environment, :name => :environment_1) }
|
18
|
+
let(:environment_2) { stub(:Environment2, :node_type => :environment, :name => :environment_2, :servers => [server_1, server_2, server_3]) }
|
19
|
+
|
20
|
+
let(:project_1) { stub(:Project1, :node_type => :project, :name => :project_1, :environments => [environment_1, environment_2]) }
|
21
|
+
let(:project_2) { stub(:Project2, :node_type => :project, :name => :project_2) }
|
22
|
+
|
23
|
+
let(:config) { stub(:Config, :node_type => :config, :projects => [project_1, project_2], :name => :config) }
|
24
|
+
|
25
|
+
let(:traverser) { described_class.new(config) }
|
26
|
+
|
27
|
+
before do
|
28
|
+
config.stub(:has_nodes?).with(:projects).and_return(true)
|
29
|
+
config.stub(:nodes).with(:projects).and_return([project_1, project_2])
|
30
|
+
|
31
|
+
project_1.stub(:has_nodes?).with(:environments).and_return(true)
|
32
|
+
project_1.stub(:nodes).with(:environments).and_return([environment_1, environment_2])
|
33
|
+
|
34
|
+
project_2.stub(:has_nodes?).with(:environments).and_return(false)
|
35
|
+
project_2.should_not_receive(:nodes)
|
36
|
+
|
37
|
+
environment_1.stub(:has_nodes?).with(:servers).and_return(false)
|
38
|
+
environment_1.should_not_receive(:nodes)
|
39
|
+
|
40
|
+
environment_2.stub(:has_nodes?).with(:servers).and_return(true)
|
41
|
+
environment_2.stub(:nodes).and_return([server_1, server_2, server_3])
|
42
|
+
end
|
43
|
+
|
44
|
+
class PrintingVisitor
|
45
|
+
def initialize
|
46
|
+
@result = []
|
47
|
+
end
|
48
|
+
|
49
|
+
def visit(type)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#visit_depth_first" do
|
54
|
+
it "traverses in depth with visitor" do
|
55
|
+
visitor = stub(:Visitor)
|
56
|
+
[config, project_1, environment_1, environment_2, server_1, server_2, server_3, project_2].each do |node|
|
57
|
+
visitor.should_receive(:visit).with(node).ordered
|
58
|
+
end
|
59
|
+
traverser.visit_depth_first(visitor)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|