the-maestro 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/.document +5 -0
  2. data/.gitignore +25 -0
  3. data/LICENSE +23 -0
  4. data/README.rdoc +378 -0
  5. data/Rakefile +116 -0
  6. data/VERSION +1 -0
  7. data/lib/maestro.rb +354 -0
  8. data/lib/maestro/cloud.rb +384 -0
  9. data/lib/maestro/cloud/aws.rb +1231 -0
  10. data/lib/maestro/dsl_property.rb +15 -0
  11. data/lib/maestro/log4r/console_formatter.rb +18 -0
  12. data/lib/maestro/log4r/file_formatter.rb +24 -0
  13. data/lib/maestro/node.rb +123 -0
  14. data/lib/maestro/operating_system.rb +53 -0
  15. data/lib/maestro/operating_system/cent_os.rb +23 -0
  16. data/lib/maestro/operating_system/debian.rb +40 -0
  17. data/lib/maestro/operating_system/fedora.rb +23 -0
  18. data/lib/maestro/operating_system/ubuntu.rb +100 -0
  19. data/lib/maestro/role.rb +36 -0
  20. data/lib/maestro/tasks.rb +52 -0
  21. data/lib/maestro/validator.rb +32 -0
  22. data/rails/init.rb +1 -0
  23. data/test/integration/base_aws.rb +156 -0
  24. data/test/integration/fixtures/config/maestro/cookbooks/emacs/metadata.json +41 -0
  25. data/test/integration/fixtures/config/maestro/cookbooks/emacs/metadata.rb +3 -0
  26. data/test/integration/fixtures/config/maestro/cookbooks/emacs/recipes/default.rb +21 -0
  27. data/test/integration/fixtures/config/maestro/roles/default.json +9 -0
  28. data/test/integration/fixtures/config/maestro/roles/web.json +9 -0
  29. data/test/integration/helper.rb +8 -0
  30. data/test/integration/test_aws_cloud.rb +805 -0
  31. data/test/integration/test_cent_os.rb +104 -0
  32. data/test/integration/test_debian.rb +119 -0
  33. data/test/integration/test_fedora.rb +104 -0
  34. data/test/integration/test_ubuntu.rb +149 -0
  35. data/test/unit/fixtures/invalid-clouds-not-a-directory/config/maestro/clouds +1 -0
  36. data/test/unit/fixtures/invalid-cookbooks-not-a-directory/config/maestro/cookbooks +0 -0
  37. data/test/unit/fixtures/invalid-maestro-not-a-directory/config/maestro +0 -0
  38. data/test/unit/fixtures/invalid-missing-cookbooks/config/maestro/clouds/valid.yml +21 -0
  39. data/test/unit/fixtures/invalid-missing-roles/config/maestro/clouds/valid.yml +21 -0
  40. data/test/unit/fixtures/invalid-roles-not-a-directory/config/maestro/roles +1 -0
  41. data/test/unit/fixtures/ssh/id_rsa-maestro-test-keypair +27 -0
  42. data/test/unit/helper.rb +6 -0
  43. data/test/unit/test_aws_cloud.rb +133 -0
  44. data/test/unit/test_aws_ec2_node.rb +76 -0
  45. data/test/unit/test_aws_elb_node.rb +221 -0
  46. data/test/unit/test_aws_rds_node.rb +380 -0
  47. data/test/unit/test_cent_os.rb +28 -0
  48. data/test/unit/test_cloud.rb +142 -0
  49. data/test/unit/test_debian.rb +62 -0
  50. data/test/unit/test_fedora.rb +28 -0
  51. data/test/unit/test_invalid_mode.rb +11 -0
  52. data/test/unit/test_maestro.rb +140 -0
  53. data/test/unit/test_node.rb +50 -0
  54. data/test/unit/test_operating_system.rb +19 -0
  55. data/test/unit/test_rails_mode.rb +77 -0
  56. data/test/unit/test_role.rb +59 -0
  57. data/test/unit/test_standalone_mode.rb +75 -0
  58. data/test/unit/test_ubuntu.rb +95 -0
  59. data/the-maestro.gemspec +150 -0
  60. metadata +228 -0
@@ -0,0 +1,21 @@
1
+ provider: ec2
2
+ provider_config:
3
+ aws_account_id: XXXX-XXXX-XXXX
4
+ aws_access_key: XXXXXXXXXXXXXXXXXXXX
5
+ aws_secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6
+ keypair_name: maestro-test-keypair
7
+ keypair_file: /home/foo/id_rsa-maestro-test-keypair
8
+
9
+ roles:
10
+ web:
11
+ public_ports: [80, 443]
12
+ db-master: {}
13
+
14
+ nodes:
15
+ test-1.maestro-rails-test.node:
16
+ # Node -> Role mapping
17
+ roles: [web, db-master]
18
+ provider_config:
19
+ ami: ami-XXXXXXXX
20
+ instance_type: m1.small
21
+ availability_zone: us-east-1b
@@ -0,0 +1,21 @@
1
+ provider: ec2
2
+ provider_config:
3
+ aws_account_id: XXXX-XXXX-XXXX
4
+ aws_access_key: XXXXXXXXXXXXXXXXXXXX
5
+ aws_secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6
+ keypair_name: maestro-test-keypair
7
+ keypair_file: /home/foo/id_rsa-maestro-test-keypair
8
+
9
+ roles:
10
+ web:
11
+ public_ports: [80, 443]
12
+ db-master: {}
13
+
14
+ nodes:
15
+ test-1.maestro-rails-test.node:
16
+ # Node -> Role mapping
17
+ roles: [web, db-master]
18
+ provider_config:
19
+ ami: ami-XXXXXXXX
20
+ instance_type: m1.small
21
+ availability_zone: us-east-1b
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEowIBAAKCAQEApiOBafftYOaMlJkP+xrVf/0ULMCZ0VUk42EigDA6t8cloejW
3
+ HAR5NJ8k6wlOiszvoSpb2Pi+tLPfDOwHzJCl3DSvn1kVpmozC7CyZwz0+67JBRus
4
+ LgJMR2zzlBnFql55MV9a0XxYlOGNnvvYlSqrgwzSnMONU9X8br9AX7Ivjt5Dkk95
5
+ +bnShrSVop0vF0K1dWkWFFbmaKnYBkzKD2Rt6w1Wblm5geW74FLQYIxWzKiz0WZI
6
+ lX74A1BsYpvp6viVZXX3hw7LYuLTHYIyz/sKgupzItw+kaKJK8B1reP/RKuD1Alg
7
+ AWxuAEcH2zSDU+2FxDYfJKoMELN4BgVZF1gFBQIDAQABAoIBADcsK1oJn6dCaQUg
8
+ H5KAQs6SORTzkSFXaTypkU+ItLc7R2ARdqkvQyEaiKQVHyQxEpMvAfl4Abz4zuX3
9
+ rE9e6fXK+Vetuebd9b24HEbkoqbCULeFjRRqZvKBWBKizGXbodunkv1mkfQ/Q0y8
10
+ zhwbY4HNzFOLDW/97CrLEJG3FtwWorcugYr2acilVV6z4R5uxcuuDGSK1GM7dvwR
11
+ tMZ2tJCRwpNuw3fH7nW+zcjk/x8fhC69IvtjuCaQPdMhuUeuRAEi4lC/ryka9WQ+
12
+ kNuGlPrLPsDAQtfJHL40XEUH/MH4GvCg4v002OD8XaDpYxASWuHrHv3a1o5KFG8r
13
+ hHARtwECgYEA11+SKqE2PM2avHSS37sEee/FVWjW6wCn7vT3V63yqKrMLkhwkwHw
14
+ zDzBC+XYsbilRwKHQNIJ8vhXEWurqJie4c/ZmUa/rpT76PWOKubUFxc1oQf37mrj
15
+ jM+N6jmbK7f9+odmpJET1nyc8s3ROV4c4iom+ftHEkX8sS0vxeTxbrECgYEAxXph
16
+ 7hNl1yJEvAIgtT5qIKyxcYBFHIFehrD3hlPydtOusx7KWG/rc+CUICL3reAJ+SHa
17
+ KfZ5iruMegZsXmHV0tUwTOTd9TnPaEKJfxByFYQTX5XAXxzdtA1UD/pr553vZVgq
18
+ Pb5DWQKXU1TqatTE44ot/9bi2nFzytTh9CwSGJUCgYAoTZIkuBZWOoOCUK5Lf8vO
19
+ pbffy8asI2tJpD3FAqAuQAgFgTjPycUt8xCNEW4Dk/IZ37c/wg5qkV55vBRbcHQK
20
+ /cJSlJK6MNcTOSBpltiJmaZHhB45V3dNmmmMM0t+WugEQeJLWXrE4HzeUvWcLqhp
21
+ CkpQ7VzXZpFq9nHCLp2fgQKBgBeh/MREGAT1+enSC14FWSgN4rJlml+977UIyqaN
22
+ t0+XJ6oR/j81LaVRdAighqmNTUQ+U+B/ua3rofUcfa2R4cf4cW5SWWm2gGbGx7Oo
23
+ IS8H/lWLE1mOl82rZqr+2hj+4p5rParj8SVe1QNI/0DHs8RTTgv3CHEB8MyOS3gw
24
+ Kf49AoGBALhv8PiSNyMtDj3BGtB6Mfs/8tg0Zbk+c4P0A52ppNA7414OqVx0A1ML
25
+ VIw2kOU19Yj6CmRyzBZLeTDaWArwEYyDEblWs9tklI7HNAR3KfW/ptp8XrYT+w98
26
+ N5BkWOgV7Zcr90vj9WbAMr4bQHi2SoXG2zSKagUuoQ6hblDdUZxT
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+ require 'maestro'
6
+ require 'shoulda'
@@ -0,0 +1,133 @@
1
+ require 'helper'
2
+
3
+ # Unit tests for Maestro::Cloud::Aws
4
+ class TestAwsCloud < Test::Unit::TestCase
5
+
6
+ context "Maestro::Cloud::Aws" do
7
+ setup do
8
+ @cloud = aws_cloud :test do
9
+ keypair_name "XXXXXXX-keypair"
10
+ keypair_file "/path/to/id_rsa-XXXXXXX-keypair"
11
+ aws_account_id "XXXX-XXXX-XXXX"
12
+ aws_access_key "XXXXXXXXXXXXXXXXXXXX"
13
+ aws_secret_access_key "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
14
+ chef_bucket "maestro.mydomain.com"
15
+
16
+ roles do
17
+ role "web" do
18
+ public_ports [80, 443]
19
+ end
20
+ end
21
+
22
+ nodes do
23
+ ec2_node "web-1" do
24
+ roles ["web"]
25
+ ami "ami-bb709dd2"
26
+ ssh_user "ubuntu"
27
+ instance_type "m1.small"
28
+ availability_zone "us-east-1b"
29
+ elastic_ip "111.111.11.111"
30
+ ebs_volume_id "vol-XXXXXXXX"
31
+ ebs_device "/dev/sdh"
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ should "be invalid due to duplicate ec2 nodes" do
38
+ cloud = aws_cloud :test do
39
+ keypair_name "XXXXXXX-keypair"
40
+ keypair_file "/path/to/id_rsa-XXXXXXX-keypair"
41
+ aws_account_id "XXXX-XXXX-XXXX"
42
+ aws_access_key "XXXXXXXXXXXXXXXXXXXX"
43
+ aws_secret_access_key "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
44
+ chef_bucket "maestro.mydomain.com"
45
+
46
+ roles {}
47
+
48
+ nodes do
49
+ ec2_node "web-1" do
50
+ roles ["web"]
51
+ ami "ami-bb709dd2"
52
+ ssh_user "ubuntu"
53
+ instance_type "m1.small"
54
+ availability_zone "us-east-1b"
55
+ elastic_ip "111.111.11.111"
56
+ ebs_volume_id "vol-XXXXXXXX"
57
+ ebs_device "/dev/sdh"
58
+ end
59
+ ec2_node "web-1" do
60
+ roles ["web"]
61
+ ami "ami-bb709dd2"
62
+ ssh_user "ubuntu"
63
+ instance_type "m1.small"
64
+ availability_zone "us-east-1b"
65
+ elastic_ip "111.111.11.111"
66
+ ebs_volume_id "vol-XXXXXXXX"
67
+ ebs_device "/dev/sdh"
68
+ end
69
+ end
70
+ end
71
+ cloud.validate
72
+ assert !cloud.valid?
73
+ assert cloud.validation_errors.any? {|message| !message.index("Duplicate node definition: web-1").nil?}
74
+ end
75
+
76
+ should "be invalid due to duplicate elb nodes" do
77
+ cloud = aws_cloud :test do
78
+ keypair_name "XXXXXXX-keypair"
79
+ keypair_file "/path/to/id_rsa-XXXXXXX-keypair"
80
+ aws_account_id "XXXX-XXXX-XXXX"
81
+ aws_access_key "XXXXXXXXXXXXXXXXXXXX"
82
+ aws_secret_access_key "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
83
+ chef_bucket "maestro.mydomain.com"
84
+
85
+ roles {}
86
+
87
+ nodes do
88
+ elb_node "lb-1" do
89
+ end
90
+ elb_node "lb-1" do
91
+ end
92
+ end
93
+ end
94
+ cloud.validate
95
+ assert !cloud.valid?
96
+ assert cloud.validation_errors.any? {|message| !message.index("Duplicate node definition: lb-1").nil?}
97
+ end
98
+
99
+ should "be invalid due to missing aws access key" do
100
+ @cloud.aws_access_key nil
101
+ @cloud.validate
102
+ assert !@cloud.valid?
103
+ assert @cloud.validation_errors.any? {|message| !message.index("Missing aws_access_key").nil? }
104
+ end
105
+
106
+ should "be invalid due to missing aws account id" do
107
+ @cloud.aws_account_id nil
108
+ @cloud.validate
109
+ assert !@cloud.valid?
110
+ assert @cloud.validation_errors.any? {|message| !message.index("Missing aws_account_id").nil? }
111
+ end
112
+
113
+ should "be invalid due to missing aws secret access key" do
114
+ @cloud.aws_secret_access_key nil
115
+ @cloud.validate
116
+ assert !@cloud.valid?
117
+ assert @cloud.validation_errors.any? {|message| !message.index("Missing aws_secret_access_key").nil? }
118
+ end
119
+
120
+ should "be invalid due to missing chef bucket" do
121
+ @cloud.chef_bucket nil
122
+ @cloud.validate
123
+ assert !@cloud.valid?
124
+ assert @cloud.validation_errors.any? {|message| !message.index("Missing chef_bucket").nil? }
125
+ end
126
+
127
+ should "be valid" do
128
+ @cloud.validate
129
+ assert @cloud.valid?
130
+ assert @cloud.validation_errors.empty?
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,76 @@
1
+ require 'helper'
2
+
3
+ # Unit tests for Maestro::Node::Aws::Ec2
4
+ class TestAwsEc2Node < Test::Unit::TestCase
5
+
6
+ context "Maestro::Node::Aws::Ec2" do
7
+ setup do
8
+ @cloud = aws_cloud :test do
9
+ roles do
10
+ role "web" do
11
+ public_ports [80, 443]
12
+ end
13
+ end
14
+
15
+ nodes do
16
+ ec2_node "web-1" do
17
+ roles ["web"]
18
+ ami "ami-bb709dd2"
19
+ ssh_user "ubuntu"
20
+ instance_type "m1.small"
21
+ availability_zone "us-east-1b"
22
+ elastic_ip "111.111.11.111"
23
+ ebs_volume_id "vol-XXXXXXXX"
24
+ ebs_device "/dev/sdh"
25
+ end
26
+ end
27
+ end
28
+ @node = @cloud.nodes["web-1"]
29
+ end
30
+
31
+ should "be an Ec2 node" do
32
+ assert @node.is_a? Maestro::Node::Aws::Ec2
33
+ end
34
+
35
+ should "be invalid due to node missing ami" do
36
+ @node.ami nil
37
+ @node.validate
38
+ assert !@node.valid?
39
+ assert @node.validation_errors.any? {|message| !message.index("missing ami").nil? }
40
+ end
41
+
42
+ should "be invalid due to node missing instance type" do
43
+ @node.instance_type nil
44
+ @node.validate
45
+ assert !@node.valid?
46
+ assert @node.validation_errors.any? {|message| !message.index("missing instance_type").nil? }
47
+ end
48
+
49
+ should "be invalid due to node missing availability zone" do
50
+ @node.availability_zone nil
51
+ @node.validate
52
+ assert !@node.valid?
53
+ assert @node.validation_errors.any? {|message| !message.index("missing availability_zone").nil? }
54
+ end
55
+
56
+ should "be invalid due to node missing ebs_device" do
57
+ @node.ebs_device nil
58
+ @node.validate
59
+ assert !@node.valid?
60
+ assert @node.validation_errors.any? {|message| !message.index("missing ebs_device").nil? }
61
+ end
62
+
63
+ should "be invalid due to node missing ebs_volume_id" do
64
+ @node.ebs_volume_id nil
65
+ @node.validate
66
+ assert !@node.valid?
67
+ assert @node.validation_errors.any? {|message| !message.index("missing ebs_volume_id").nil? }
68
+ end
69
+
70
+ should "be valid" do
71
+ @node.validate
72
+ assert @node.valid?
73
+ assert @node.validation_errors.empty?
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,221 @@
1
+ require 'helper'
2
+
3
+ # Unit tests for Maestro::Node::Aws::Elb
4
+ class TestAwsElbNode < Test::Unit::TestCase
5
+
6
+ context "Maestro::Node::Aws::Elb" do
7
+ setup do
8
+ @cloud = aws_cloud :test do
9
+ roles {}
10
+
11
+ nodes do
12
+ ec2_node "web-1" do end
13
+
14
+ elb_node "lb-1" do
15
+ availability_zones ["us-east-1b"]
16
+ listeners [{:load_balancer_port => 80, :instance_port => 80, :protocol => "http"}]
17
+ ec2_nodes ["web-1"]
18
+ health_check(:target => "TCP:80", :timeout => 15, :interval => 60, :unhealthy_threshold => 5, :healthy_threshold => 3)
19
+ end
20
+ end
21
+ end
22
+ @node = @cloud.nodes["lb-1"]
23
+ end
24
+
25
+ should "be an Elb node" do
26
+ assert @node.is_a? Maestro::Node::Aws::Elb
27
+ end
28
+
29
+ should "be invalid due to name too long" do
30
+ cloud = aws_cloud :test do
31
+ roles {}
32
+ nodes do
33
+ ec2_node "web-1" do end
34
+ elb_node "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX123" do end
35
+ end
36
+ end
37
+ node = cloud.nodes["XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX123"]
38
+ node.validate
39
+ assert !node.valid?
40
+ assert node.validation_errors.any? {|message| !message.index("name must be less than 32 characters").nil?}
41
+ end
42
+
43
+ should "be invalid due to name containing invalid characters" do
44
+ "!@\#$%^&*()_=+~`\"{[}]\\|/?.>,<".each_char do |char|
45
+ cloud = aws_cloud :test do
46
+ roles {}
47
+ nodes do
48
+ ec2_node "web-1" do end
49
+ elb_node "#{char}" do end
50
+ end
51
+ end
52
+ node = cloud.nodes["#{char}"]
53
+ node.validate
54
+ assert !node.valid?
55
+ assert node.validation_errors.any? {|message| !message.index("name may only contain alphanumerics and hyphens").nil?}
56
+ end
57
+ end
58
+
59
+ should "be invalid due to name not starting with a letter" do
60
+ "0123456789!@\#$%^&*()_=+~`\"{[}]\\|/?.>,<".each_char do |char|
61
+ cloud = aws_cloud :test do
62
+ roles {}
63
+ nodes do
64
+ ec2_node "web-1" do end
65
+ elb_node "#{char}" do end
66
+ end
67
+ end
68
+ node = cloud.nodes["#{char}"]
69
+ node.validate
70
+ assert !node.valid?
71
+ assert node.validation_errors.any? {|message| !message.index("name must start with a letter").nil?}
72
+ end
73
+ end
74
+
75
+ should "be invalid due to name ending with hyphen" do
76
+ cloud = aws_cloud :test do
77
+ roles {}
78
+ nodes do
79
+ ec2_node "web-1" do end
80
+ elb_node "test-" do end
81
+ end
82
+ end
83
+ node = cloud.nodes["test-"]
84
+ node.validate
85
+ assert !node.valid?
86
+ assert node.validation_errors.any? {|message| !message.index("name must not end with a hypen").nil?}
87
+ end
88
+
89
+ should "be invalid due to name containing two consecutive hyphens" do
90
+ cloud = aws_cloud :test do
91
+ roles {}
92
+ nodes do
93
+ ec2_node "web-1" do end
94
+ elb_node "te--st" do end
95
+ end
96
+ end
97
+ node = cloud.nodes["te--st"]
98
+ node.validate
99
+ assert !node.valid?
100
+ assert node.validation_errors.any? {|message| !message.index("name must not contain two consecutive hyphens").nil?}
101
+ end
102
+
103
+ should "be invalid due to missing listeners" do
104
+ @node.listeners nil
105
+ @node.validate
106
+ assert !@node.valid?
107
+ assert @node.validation_errors.any? {|message| !message.index("node missing listeners").nil? }
108
+ end
109
+
110
+ should "be invalid due to listeners not an array" do
111
+ @node.listeners "foo"
112
+ @node.validate
113
+ assert !@node.valid?
114
+ assert @node.validation_errors.any? {|message| !message.index("node's listeners must be an Array of Hashes").nil? }
115
+ end
116
+
117
+ should "be invalid due to listeners element not a Hash" do
118
+ @node.listeners[0] = "foo"
119
+ @node.validate
120
+ assert !@node.valid?
121
+ assert @node.validation_errors.any? {|message| !message.index("node's listeners must be an Array of Hashes").nil? }
122
+ end
123
+
124
+ should "be invalid due to missing load_balancer_port" do
125
+ @node.listeners[0].delete(:load_balancer_port)
126
+ @node.validate
127
+ assert !@node.valid?
128
+ assert @node.validation_errors.any? {|message| !message.index("node's listeners Hash missing :load_balancer_port key").nil? }
129
+ end
130
+
131
+ should "be invalid due to missing instance_port" do
132
+ @node.listeners[0].delete(:instance_port)
133
+ @node.validate
134
+ assert !@node.valid?
135
+ assert @node.validation_errors.any? {|message| !message.index("node's listeners Hash missing :instance_port key").nil? }
136
+ end
137
+
138
+ should "be invalid due to missing protocol" do
139
+ @node.listeners[0].delete(:protocol)
140
+ @node.validate
141
+ assert !@node.valid?
142
+ assert @node.validation_errors.any? {|message| !message.index("node's listeners Hash missing :protocol key").nil? }
143
+ end
144
+
145
+ should "be invalid due to missing ec2_nodes" do
146
+ @node.ec2_nodes nil
147
+ @node.validate
148
+ assert !@node.valid?
149
+ assert @node.validation_errors.any? {|message| !message.index("node missing ec2_nodes collection").nil? }
150
+ end
151
+
152
+ should "be invalid due to ec2_nodes not an array" do
153
+ @node.ec2_nodes 1
154
+ @node.validate
155
+ assert !@node.valid?
156
+ assert @node.validation_errors.any? {|message| !message.index("node ec2_nodes collection is not an Array ").nil? }
157
+ end
158
+
159
+ should "be invalid due to missing availability_zones" do
160
+ @node.availability_zones nil
161
+ @node.validate
162
+ assert !@node.valid?
163
+ assert @node.validation_errors.any? {|message| !message.index("node missing availability_zones collection").nil? }
164
+ end
165
+
166
+ should "be invalid due to availability_zones not an array" do
167
+ @node.availability_zones 1
168
+ @node.validate
169
+ assert !@node.valid?
170
+ assert @node.validation_errors.any? {|message| !message.index("node availability_zones collection is not an Array ").nil? }
171
+ end
172
+
173
+ should "be invalid due to health_check element not a Hash" do
174
+ @node.health_check "foo"
175
+ @node.validate
176
+ assert !@node.valid?
177
+ assert @node.validation_errors.any? {|message| !message.index("node's health_check must be a Hash").nil? }
178
+ end
179
+
180
+ should "be invalid due to missing target" do
181
+ @node.health_check.delete(:target)
182
+ @node.validate
183
+ assert !@node.valid?
184
+ assert @node.validation_errors.any? {|message| !message.index("node's health_check Hash missing :target key").nil? }
185
+ end
186
+
187
+ should "be invalid due to missing timeout" do
188
+ @node.health_check.delete(:timeout)
189
+ @node.validate
190
+ assert !@node.valid?
191
+ assert @node.validation_errors.any? {|message| !message.index("node's health_check Hash missing :timeout key").nil? }
192
+ end
193
+
194
+ should "be invalid due to missing interval" do
195
+ @node.health_check.delete(:interval)
196
+ @node.validate
197
+ assert !@node.valid?
198
+ assert @node.validation_errors.any? {|message| !message.index("node's health_check Hash missing :interval key").nil? }
199
+ end
200
+
201
+ should "be invalid due to missing unhealthy_threshold" do
202
+ @node.health_check.delete(:unhealthy_threshold)
203
+ @node.validate
204
+ assert !@node.valid?
205
+ assert @node.validation_errors.any? {|message| !message.index("node's health_check Hash missing :unhealthy_threshold key").nil? }
206
+ end
207
+
208
+ should "be invalid due to missing healthy_threshold" do
209
+ @node.health_check.delete(:healthy_threshold)
210
+ @node.validate
211
+ assert !@node.valid?
212
+ assert @node.validation_errors.any? {|message| !message.index("node's health_check Hash missing :healthy_threshold key").nil? }
213
+ end
214
+
215
+ should "be valid" do
216
+ @node.validate
217
+ assert @node.valid?
218
+ assert @node.validation_errors.empty?
219
+ end
220
+ end
221
+ end