the-maestro 0.2.0

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 (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