aws-codedeploy-agent 0.0.1

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 (84) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGES.md +3 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +177 -0
  5. data/NOTICE +2 -0
  6. data/README.md +16 -0
  7. data/aws-codedeploy-agent.gemspec +39 -0
  8. data/bin/codedeploy-agent +78 -0
  9. data/bin/codedeploy-install +15 -0
  10. data/bin/codedeploy-uninstall +13 -0
  11. data/certs/host-agent-deployment-signer-ca-chain.pem +76 -0
  12. data/conf/codedeployagent.yml +9 -0
  13. data/init.d/codedeploy-agent +61 -0
  14. data/lib/core_ext.rb +71 -0
  15. data/lib/instance_agent.rb +35 -0
  16. data/lib/instance_agent/agent/base.rb +34 -0
  17. data/lib/instance_agent/codedeploy_plugin/application_specification/ace_info.rb +133 -0
  18. data/lib/instance_agent/codedeploy_plugin/application_specification/acl_info.rb +163 -0
  19. data/lib/instance_agent/codedeploy_plugin/application_specification/application_specification.rb +142 -0
  20. data/lib/instance_agent/codedeploy_plugin/application_specification/context_info.rb +23 -0
  21. data/lib/instance_agent/codedeploy_plugin/application_specification/file_info.rb +23 -0
  22. data/lib/instance_agent/codedeploy_plugin/application_specification/linux_permission_info.rb +121 -0
  23. data/lib/instance_agent/codedeploy_plugin/application_specification/mode_info.rb +66 -0
  24. data/lib/instance_agent/codedeploy_plugin/application_specification/range_info.rb +134 -0
  25. data/lib/instance_agent/codedeploy_plugin/application_specification/script_info.rb +27 -0
  26. data/lib/instance_agent/codedeploy_plugin/codedeploy_control.rb +72 -0
  27. data/lib/instance_agent/codedeploy_plugin/command_executor.rb +357 -0
  28. data/lib/instance_agent/codedeploy_plugin/command_poller.rb +146 -0
  29. data/lib/instance_agent/codedeploy_plugin/deployment_specification.rb +150 -0
  30. data/lib/instance_agent/codedeploy_plugin/hook_executor.rb +206 -0
  31. data/lib/instance_agent/codedeploy_plugin/install_instruction.rb +374 -0
  32. data/lib/instance_agent/codedeploy_plugin/installer.rb +143 -0
  33. data/lib/instance_agent/codedeploy_plugin/request_helper.rb +28 -0
  34. data/lib/instance_agent/config.rb +43 -0
  35. data/lib/instance_agent/log.rb +3 -0
  36. data/lib/instance_agent/platform.rb +17 -0
  37. data/lib/instance_agent/platform/linux_util.rb +57 -0
  38. data/lib/instance_agent/runner/child.rb +57 -0
  39. data/lib/instance_agent/runner/master.rb +103 -0
  40. data/lib/instance_metadata.rb +47 -0
  41. data/test/certificate_helper.rb +120 -0
  42. data/test/helpers/instance_agent_helper.rb +25 -0
  43. data/test/instance_agent/agent/base_test.rb +49 -0
  44. data/test/instance_agent/codedeploy_plugin/application_specification_test.rb +1710 -0
  45. data/test/instance_agent/codedeploy_plugin/codedeploy_control_test.rb +51 -0
  46. data/test/instance_agent/codedeploy_plugin/command_executor_test.rb +513 -0
  47. data/test/instance_agent/codedeploy_plugin/command_poller_test.rb +459 -0
  48. data/test/instance_agent/codedeploy_plugin/deployment_specification_test.rb +335 -0
  49. data/test/instance_agent/codedeploy_plugin/hook_executor_test.rb +250 -0
  50. data/test/instance_agent/codedeploy_plugin/install_instruction_test.rb +566 -0
  51. data/test/instance_agent/codedeploy_plugin/installer_test.rb +519 -0
  52. data/test/instance_agent/codedeploy_plugin/request_helper_test.rb +37 -0
  53. data/test/instance_agent/config_test.rb +64 -0
  54. data/test/instance_agent/runner/child_test.rb +87 -0
  55. data/test/instance_metadata_test.rb +97 -0
  56. data/test/test_helper.rb +16 -0
  57. data/vendor/gems/.codedeploy-commands-1.0.0.created.rid +1 -0
  58. data/vendor/gems/codedeploy-commands/apis/CodeDeployCommand.api.json +372 -0
  59. data/vendor/gems/codedeploy-commands/codedeploy-commands-1.0.0.gemspec +28 -0
  60. data/vendor/gems/codedeploy-commands/lib/aws/codedeploy_commands.rb +18 -0
  61. data/vendor/gems/codedeploy-commands/lib/aws/plugins/certificate_authority.rb +12 -0
  62. data/vendor/gems/codedeploy-commands/lib/aws/plugins/deploy_control_endpoint.rb +22 -0
  63. data/vendor/gems/process_manager/README.md +1 -0
  64. data/vendor/gems/process_manager/lib/blank.rb +153 -0
  65. data/vendor/gems/process_manager/lib/core_ext.rb +73 -0
  66. data/vendor/gems/process_manager/lib/process_manager.rb +49 -0
  67. data/vendor/gems/process_manager/lib/process_manager/child.rb +119 -0
  68. data/vendor/gems/process_manager/lib/process_manager/config.rb +112 -0
  69. data/vendor/gems/process_manager/lib/process_manager/log.rb +107 -0
  70. data/vendor/gems/process_manager/lib/process_manager/master.rb +322 -0
  71. data/vendor/gems/process_manager/process_manager-0.0.13.gemspec +42 -0
  72. data/vendor/specifications/aws-sdk-core-2.0.5.gemspec +39 -0
  73. data/vendor/specifications/builder-3.2.2.gemspec +29 -0
  74. data/vendor/specifications/codedeploy-commands-1.0.0.gemspec +28 -0
  75. data/vendor/specifications/gli-2.5.6.gemspec +51 -0
  76. data/vendor/specifications/jamespath-0.5.1.gemspec +35 -0
  77. data/vendor/specifications/little-plugger-1.1.3.gemspec +32 -0
  78. data/vendor/specifications/logging-1.8.1.gemspec +44 -0
  79. data/vendor/specifications/multi_json-1.7.7.gemspec +30 -0
  80. data/vendor/specifications/multi_json-1.8.4.gemspec +30 -0
  81. data/vendor/specifications/multi_xml-0.5.5.gemspec +30 -0
  82. data/vendor/specifications/process_manager-0.0.13.gemspec +42 -0
  83. data/vendor/specifications/simple_pid-0.2.1.gemspec +28 -0
  84. metadata +377 -0
@@ -0,0 +1,51 @@
1
+ require 'instance_metadata'
2
+
3
+ class CodeDeployControlTest < InstanceAgentTestCase
4
+
5
+ include InstanceAgent::CodeDeployPlugin
6
+
7
+ context "The CodeDeploy interface client" do
8
+
9
+ context "when initializing" do
10
+ setup do
11
+ ENV['AWS_ACCESS_KEY_ID'] = "Test Access Key"
12
+ ENV['AWS_SECRET_ACCESS_KEY'] = "Test Secret Access Key"
13
+ ENV['AWS_REGION'] = nil
14
+ ENV['AWSDEPLOY_CONTROL_ENDPOINT'] = "https://tempuri"
15
+ end
16
+
17
+ context "with region, endpoint and credentials" do
18
+ should "successfully initialize" do
19
+ codedeploy_control_client = CodeDeployControl.new(:region => "us-west-2")
20
+ codedeploy_control_client.get_client
21
+ end
22
+ end
23
+
24
+ context "without a region" do
25
+ should "raise an exception" do
26
+ assert_raise {
27
+ codedeploy_control_client = CodeDeployControl.new()
28
+ codedeploy_control_client.get_client
29
+ }
30
+ end
31
+ end
32
+
33
+ context "without an endpoint" do
34
+ setup do
35
+ ENV['AWS_DEPLOY_CONTROL_ENDPOINT'] = nil
36
+ end
37
+
38
+ should "raise an exception" do
39
+ assert_raise {
40
+ codedeploy_control_client = CodeDeployControl.new(:region => "us-west-2")
41
+ codedeploy_control_client.get_client.put_host_command_complete(
42
+ :command_status => 'Succeeded',
43
+ :diagnostics => nil,
44
+ :host_command_identifier => "TestCommand")
45
+
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,513 @@
1
+ require 'test_helper'
2
+ require 'stringio'
3
+ require 'instance_agent/codedeploy_plugin/installer'
4
+ require 'com/amazon/codedeploy/command/v20141006/host_command_instance'
5
+ require 'aws-sdk-core/s3'
6
+
7
+ class CodeDeployPluginCommandExecutorTest < InstanceAgentTestCase
8
+
9
+ include InstanceAgent::CodeDeployPlugin
10
+
11
+ context 'The CodeDeploy Plugin Command Executor' do
12
+ setup do
13
+ @test_hook_mapping = { "BeforeELBRemove"=>["BeforeELBRemove"],
14
+ "AfterELBRemove"=>["AfterELBRemove"],
15
+ "ApplicationStop"=>["ApplicationStop"],
16
+ "BeforeInstall"=>["BeforeInstall"],
17
+ "AfterInstall"=>["AfterInstall"],
18
+ "ApplicationStart"=>["ApplicationStart"],
19
+ "BeforeELBAdd"=>["BeforeELBAdd"],
20
+ "AfterELBAdd"=>["AfterELBAdd"],
21
+ "ValidateService"=>["ValidateService"]}
22
+ @deploy_control_client = mock
23
+ @command_executor = InstanceAgent::CodeDeployPlugin::CommandExecutor.new({
24
+ :deploy_control_client => @deploy_control_client,
25
+ :hook_mapping => @test_hook_mapping})
26
+ @aws_region = 'us-east-1'
27
+ InstanceMetadata.stubs(:region).returns(@aws_region)
28
+ end
29
+
30
+ context "deployment_system method" do
31
+ should "always return CodeDeploy" do
32
+ assert_equal "CodeDeploy", @command_executor.deployment_system
33
+ end
34
+ end
35
+
36
+ context "when executing a command" do
37
+ def generate_signed_message_for(map)
38
+ message = @cert_helper.sign_message(map.to_json)
39
+ spec = OpenStruct.new({ :payload => message })
40
+ spec.format = "PKCS7/JSON"
41
+
42
+ return spec
43
+ end
44
+
45
+ setup do
46
+ @cert_helper = CertificateHelper.new
47
+ @deployment_id = SecureRandom.uuid
48
+ @deployment_group_id = "foo"
49
+ @s3Revision = {
50
+ "Bucket" => "mybucket",
51
+ "Key" => "mykey",
52
+ "BundleType" => "tar"
53
+ }
54
+ @deployment_spec = generate_signed_message_for({
55
+ "DeploymentId" => @deployment_id.to_s,
56
+ "DeploymentGroupId" => @deployment_group_id,
57
+ "Revision" => {
58
+ "RevisionType" => "S3",
59
+ "S3Revision" => @s3Revision
60
+ }
61
+ })
62
+ @command = Com::Amazon::Codedeploy::Command::V20141006::HostCommandInstance.new(
63
+ :host_command_identifier => "command-1",
64
+ :deployment_execution_id => "test-execution")
65
+ @root_dir = '/tmp/codedeploy/'
66
+ @deployment_root_dir = File.join(@root_dir, @deployment_group_id.to_s, @deployment_id.to_s)
67
+ @deployment_instructions_dir = File.join(@root_dir, 'deployment-instructions')
68
+ @archive_root_dir = File.join(@deployment_root_dir, 'deployment-archive')
69
+ ProcessManager::Config.config[:root_dir] = @root_dir
70
+
71
+ FileUtils.stubs(:mkdir_p)
72
+ File.stubs(:directory?).with(@deployment_root_dir).returns(true)
73
+ @previous_install_file_location = File.join(@deployment_instructions_dir, "#{@deployment_group_id}_last_successful_install")
74
+ end
75
+
76
+ context "when executing an unknown command" do
77
+ setup do
78
+ @command.command_name = "unknown-command"
79
+ end
80
+
81
+ should "not create the deployment root directory" do
82
+ # Need to unstub the :mkdir_p method otherwise the never expectation doesn't work
83
+ FileUtils.unstub(:mkdir_p)
84
+ FileUtils.expects(:mkdir_p).never
85
+
86
+ assert_raised_with_message('Unsupported command type: unknown-command.', InstanceAgent::CodeDeployPlugin::CommandExecutor::InvalidCommandNameFailure) do
87
+ @command_executor.execute_command(@command, @deployment_spec)
88
+ end
89
+ end
90
+
91
+ should "throw an exception" do
92
+ assert_raised_with_message('Unsupported command type: unknown-command.', InstanceAgent::CodeDeployPlugin::CommandExecutor::InvalidCommandNameFailure) do
93
+ @command_executor.execute_command(@command, @deployment_spec)
94
+ end
95
+ end
96
+ end
97
+
98
+ context "when executing a valid command" do
99
+ setup do
100
+ @command.command_name = "Install"
101
+ @command_executor.stubs(:install)
102
+ end
103
+
104
+ should "create the deployment root directory" do
105
+ FileUtils.expects(:mkdir_p).with(@deployment_root_dir)
106
+
107
+ @command_executor.execute_command(@command, @deployment_spec)
108
+ end
109
+
110
+ context "when failed to create root directory" do
111
+ setup do
112
+ File.stubs(:directory?).with(@deployment_root_dir).returns(false)
113
+ end
114
+
115
+ should "raise an exception" do
116
+ assert_raised_with_message("Error creating deployment root directory #{@deployment_root_dir}") do
117
+ @command_executor.execute_command(@command, @deployment_spec)
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ context "when executing the Install command" do
124
+
125
+ setup do
126
+ @command.command_name = "Install"
127
+ InstanceAgent::CodeDeployPlugin::ApplicationSpecification::ApplicationSpecification.stubs(:parse).returns(@app_spec)
128
+ @installer = stub("installer", :install => nil)
129
+ Installer.stubs(:new).returns(@installer)
130
+ File.stubs(:exist?).with(@previous_install_file_location).returns(true)
131
+ File.stubs(:exist?).with(@archive_root_dir).returns(true)
132
+ File.stubs(:open).with(@previous_install_file_location, 'w+')
133
+ File.stubs(:open).with(@previous_install_file_location)
134
+
135
+ @app_spec = mock("parsed application specification")
136
+ File.
137
+ stubs(:read).
138
+ with("#@archive_root_dir/appspec.yml").
139
+ returns("APP SPEC")
140
+ ApplicationSpecification::ApplicationSpecification.stubs(:parse).with("APP SPEC").returns(@app_spec)
141
+ end
142
+
143
+ should "idempotently create the instructions directory" do
144
+ FileUtils.expects(:mkdir_p).with(@deployment_instructions_dir)
145
+
146
+ @command_executor.execute_command(@command, @deployment_spec)
147
+ end
148
+
149
+ should "create an appropriate Installer" do
150
+ Installer.
151
+ expects(:new).
152
+ with(:deployment_instructions_dir => @deployment_instructions_dir,
153
+ :deployment_archive_dir => @archive_root_dir).
154
+ returns(@installer)
155
+
156
+ @command_executor.execute_command(@command, @deployment_spec)
157
+ end
158
+
159
+ should "perform the installation for the current IG, revision and app spec" do
160
+ @installer.expects(:install).with(@deployment_group_id, @app_spec)
161
+
162
+ @command_executor.execute_command(@command, @deployment_spec)
163
+ end
164
+
165
+ should "write the archive root dir to the install instructions file" do
166
+ mock_file = mock
167
+ File.expects(:open).with(@previous_install_file_location, 'w+').yields(mock_file)
168
+ mock_file.expects(:write).with(@deployment_root_dir)
169
+
170
+ @command_executor.execute_command(@command, @deployment_spec)
171
+ end
172
+
173
+ end
174
+
175
+ context "when executing the DownloadBundle command" do
176
+ setup do
177
+ InstanceAgent::LinuxUtil.stubs(:extract_tar)
178
+ InstanceAgent::LinuxUtil.stubs(:extract_tgz)
179
+ @command.command_name = "DownloadBundle"
180
+ @http = mock
181
+ @mock_file = mock
182
+ Net::HTTP.stubs(:start).yields(@http)
183
+ File.stubs(:open).returns @mock_file
184
+ @mock_file.stubs(:close)
185
+ @http.stubs(:request_get)
186
+ @s3 = mock
187
+ Aws::S3::Client.stubs(:new).returns(@s3)
188
+ end
189
+
190
+ context "downloading bundle from S3" do
191
+ setup do
192
+ File.expects(:open).with(File.join(@deployment_root_dir, 'bundle.tar'), 'wb').yields(@mock_file)
193
+ @object = mock
194
+ @s3.stubs(:get_object).returns(@object)
195
+ @io = mock
196
+ @object.stubs(:etag).returns("myetag")
197
+ @deployment_spec = generate_signed_message_for({
198
+ "DeploymentId" => @deployment_id.to_s,
199
+ "DeploymentGroupId" => @deployment_group_id.to_s,
200
+ "Revision" => {
201
+ "RevisionType" => "S3",
202
+ "S3Revision" => {
203
+ "Bucket" => "mybucket",
204
+ "Key" => "mykey",
205
+ "BundleType" => "tar"
206
+ }
207
+ }
208
+ })
209
+ end
210
+
211
+ context "when setting up the S3 client" do
212
+ setup do
213
+ ENV['AWS_REGION'] = nil
214
+ InstanceMetadata.stubs(:region).returns('us-east-1')
215
+ end
216
+
217
+ should "read from the InstanceMetadata to get the region" do
218
+ InstanceMetadata.expects(:region)
219
+ @command_executor.execute_command(@command, @deployment_spec)
220
+ end
221
+ end
222
+
223
+ should "verify etag" do
224
+ @deployment_spec = generate_signed_message_for({
225
+ "DeploymentId" => @deployment_id.to_s,
226
+ "DeploymentGroupId" => @deployment_group_id.to_s,
227
+ "Revision" => {
228
+ "RevisionType" => "S3",
229
+ "S3Revision" => {
230
+ "Bucket" => "mybucket",
231
+ "Key" => "mykey",
232
+ "BundleType" => "tar",
233
+ "ETag" => "myetag"
234
+ }
235
+ }
236
+ })
237
+ @command_executor.execute_command(@command, @deployment_spec)
238
+ end
239
+
240
+ should "verify etag that contains quotations still matches" do
241
+ @object.stubs(:etag).returns("\"myetag\"")
242
+ @deployment_spec = generate_signed_message_for({
243
+ "DeploymentId" => @deployment_id.to_s,
244
+ "DeploymentGroupId" => @deployment_group_id.to_s,
245
+ "Revision" => {
246
+ "RevisionType" => "S3",
247
+ "S3Revision" => {
248
+ "Bucket" => "mybucket",
249
+ "Key" => "mykey",
250
+ "BundleType" => "tar",
251
+ "ETag" => "myetag"
252
+ }
253
+ }
254
+ })
255
+ @command_executor.execute_command(@command, @deployment_spec)
256
+ end
257
+
258
+ should "verify version" do
259
+ @object.stubs(:body).with(:bucket => "mybucket", :key => "mykey", :version_id => "myversion").returns(@io)
260
+ @deployment_spec = generate_signed_message_for({
261
+ "DeploymentId" => @deployment_id.to_s,
262
+ "DeploymentGroupId" => @deployment_group_id.to_s,
263
+ "Revision" => {
264
+ "RevisionType" => "S3",
265
+ "S3Revision" => {
266
+ "Bucket" => "mybucket",
267
+ "Key" => "mykey",
268
+ "BundleType" => "tar",
269
+ "Version" => "myversion"
270
+ }
271
+ }
272
+ })
273
+ @command_executor.execute_command(@command, @deployment_spec)
274
+ end
275
+
276
+ should "call zip for zip BundleTypes" do
277
+ @deployment_spec = generate_signed_message_for({
278
+ "DeploymentId" => @deployment_id.to_s,
279
+ "DeploymentGroupId" => @deployment_group_id.to_s,
280
+ "Revision" => {
281
+ "RevisionType" => "S3",
282
+ "S3Revision" => {
283
+ "Bucket" => "mybucket",
284
+ "Key" => "mykey",
285
+ "BundleType" => "zip"
286
+ }
287
+ }
288
+ })
289
+ Zip::File.expects(:open).with(File.join(@deployment_root_dir, 'bundle.tar'))
290
+ @command_executor.execute_command(@command, @deployment_spec)
291
+ end
292
+
293
+ should "call extract_tgz for Gzipped tar BundleTypes" do
294
+ @deployment_spec = generate_signed_message_for({
295
+ "DeploymentId" => @deployment_id.to_s,
296
+ "DeploymentGroupId" => @deployment_group_id.to_s,
297
+ "Revision" => {
298
+ "RevisionType" => "S3",
299
+ "S3Revision" => {
300
+ "Bucket" => "mybucket",
301
+ "Key" => "mykey",
302
+ "BundleType" => "tgz"
303
+ }
304
+ }
305
+ })
306
+ InstanceAgent::LinuxUtil.expects(:extract_tgz).with(File.join(@deployment_root_dir, 'bundle.tar'), @archive_root_dir)
307
+ @command_executor.execute_command(@command, @deployment_spec)
308
+ end
309
+
310
+ should "call extract_tar for tar BundleTypes" do
311
+ @deployment_spec = generate_signed_message_for({
312
+ "DeploymentId" => @deployment_id.to_s,
313
+ "DeploymentGroupId" => @deployment_group_id.to_s,
314
+ "Revision" => {
315
+ "RevisionType" => "S3",
316
+ "S3Revision" => {
317
+ "Bucket" => "mybucket",
318
+ "Key" => "mykey",
319
+ "BundleType" => "tar"
320
+ }
321
+ }
322
+ })
323
+ InstanceAgent::LinuxUtil.expects(:extract_tar).with(File.join(@deployment_root_dir, 'bundle.tar'), @archive_root_dir)
324
+ @command_executor.execute_command(@command, @deployment_spec)
325
+ end
326
+
327
+ end
328
+
329
+ should "unpack the bundle to the right directory" do
330
+ InstanceAgent::LinuxUtil.expects(:extract_tar).with(File.join(@deployment_root_dir, 'bundle.tar'), @archive_root_dir)
331
+ @command_executor.execute_command(@command, @deployment_spec)
332
+ end
333
+
334
+ should "remove the directory before unpacking" do
335
+ call_sequence = sequence("call sequence")
336
+ FileUtils.expects(:rm_rf).with(@archive_root_dir).in_sequence(call_sequence)
337
+ InstanceAgent::LinuxUtil.expects(:extract_tar).in_sequence(call_sequence)
338
+ @command_executor.execute_command(@command, @deployment_spec)
339
+ end
340
+ end
341
+
342
+ context "I have an empty app spec (for script mapping)" do
343
+ setup do
344
+ File.stubs(:read).with(File.join(@archive_root_dir, 'appspec.yml')).returns(nil)
345
+ InstanceAgent::CodeDeployPlugin::ApplicationSpecification::ApplicationSpecification.stubs(:parse).returns(nil)
346
+ @hook_executor_constructor_hash = {
347
+ :deployment_root_dir => @deployment_root_dir,
348
+ :last_successful_deployment_dir => nil,
349
+ :app_spec_path => 'appspec.yml'}
350
+ @mock_hook_executor = mock
351
+ end
352
+
353
+ context "BeforeELBRemove" do
354
+ setup do
355
+ @command.command_name = "BeforeELBRemove"
356
+ @hook_executor_constructor_hash[:lifecycle_event] = "BeforeELBRemove"
357
+ end
358
+
359
+ should "call execute a hook executor object with BeforeELBRemove as one of the params" do
360
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
361
+ @mock_hook_executor.expects(:execute)
362
+ @command_executor.execute_command(@command, @deployment_spec)
363
+ end
364
+ end
365
+
366
+ context "AfterELBRemove" do
367
+ setup do
368
+ @command.command_name = "AfterELBRemove"
369
+ @hook_executor_constructor_hash[:lifecycle_event] = "AfterELBRemove"
370
+ end
371
+
372
+ should "call execute a hook executor object with AfterELBRemove as one of the params" do
373
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
374
+ @mock_hook_executor.expects(:execute)
375
+ @command_executor.execute_command(@command, @deployment_spec)
376
+ end
377
+ end
378
+
379
+ context "ApplicationStop" do
380
+ setup do
381
+ @command.command_name = "ApplicationStop"
382
+ @hook_executor_constructor_hash[:lifecycle_event] = "ApplicationStop"
383
+ end
384
+
385
+ should "call execute a hook executor object with ApplicationStop as one of the params" do
386
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
387
+ @mock_hook_executor.expects(:execute)
388
+ @command_executor.execute_command(@command, @deployment_spec)
389
+ end
390
+ end
391
+
392
+ context "BeforeInstall" do
393
+ setup do
394
+ @command.command_name = "BeforeInstall"
395
+ @hook_executor_constructor_hash[:lifecycle_event] = "BeforeInstall"
396
+ end
397
+
398
+ should "call execute a hook executor object with BeforeInstall as one of the params" do
399
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
400
+ @mock_hook_executor.expects(:execute)
401
+ @command_executor.execute_command(@command, @deployment_spec)
402
+ end
403
+ end
404
+
405
+ context "AfterInstall" do
406
+ setup do
407
+ @command.command_name = "AfterInstall"
408
+ @hook_executor_constructor_hash[:lifecycle_event] = "AfterInstall"
409
+ end
410
+
411
+ should "call execute a hook executor object with AfterInstall as one of the params" do
412
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
413
+ @mock_hook_executor.expects(:execute)
414
+ @command_executor.execute_command(@command, @deployment_spec)
415
+ end
416
+ end
417
+
418
+ context "ApplicationStart" do
419
+ setup do
420
+ @command.command_name = "ApplicationStart"
421
+ @hook_executor_constructor_hash[:lifecycle_event] = "ApplicationStart"
422
+ end
423
+
424
+ should "call execute a hook executor object with ApplicationStart as one of the params" do
425
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
426
+ @mock_hook_executor.expects(:execute)
427
+ @command_executor.execute_command(@command, @deployment_spec)
428
+ end
429
+ end
430
+
431
+ context "BeforeELBAdd" do
432
+ setup do
433
+ @command.command_name = "BeforeELBAdd"
434
+ @hook_executor_constructor_hash[:lifecycle_event] = "BeforeELBAdd"
435
+ end
436
+
437
+ should "call execute a hook executor object with BeforeELBAdd as one of the params" do
438
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
439
+ @mock_hook_executor.expects(:execute)
440
+ @command_executor.execute_command(@command, @deployment_spec)
441
+ end
442
+ end
443
+
444
+ context "AfterELBAdd" do
445
+ setup do
446
+ @command.command_name = "AfterELBAdd"
447
+ @hook_executor_constructor_hash[:lifecycle_event] = "AfterELBAdd"
448
+ end
449
+
450
+ should "call execute a hook executor object with AfterELBAdd as one of the params" do
451
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
452
+ @mock_hook_executor.expects(:execute)
453
+ @command_executor.execute_command(@command, @deployment_spec)
454
+ end
455
+ end
456
+
457
+ context "ValidateService" do
458
+ setup do
459
+ @command.command_name = "ValidateService"
460
+ @hook_executor_constructor_hash[:lifecycle_event] = "ValidateService"
461
+ end
462
+
463
+ should "call execute a hook executor object with ValidateService as one of the params" do
464
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash).returns(@mock_hook_executor)
465
+ @mock_hook_executor.expects(:execute)
466
+ @command_executor.execute_command(@command, @deployment_spec)
467
+ end
468
+ end
469
+ end
470
+
471
+ #non 1:1 mapping tests
472
+ context "one command hooks to multiple lifecycle events" do
473
+ setup do
474
+ @command.command_name = "test_command"
475
+ @test_hook_mapping = { "test_command" => ["lifecycle_event_1","lifecycle_event_2"]}
476
+ @deploy_control_client = mock
477
+ @command_executor = InstanceAgent::CodeDeployPlugin::CommandExecutor.new({
478
+ :deploy_control_client => @deploy_control_client,
479
+ :hook_mapping => @test_hook_mapping})
480
+ hook_executor_constructor_hash = {
481
+ :deployment_root_dir => @deployment_root_dir,
482
+ :last_successful_deployment_dir => nil,
483
+ :app_spec_path => 'appspec.yml'}
484
+ @hook_executor_constructor_hash_1 = hook_executor_constructor_hash.merge({:lifecycle_event => "lifecycle_event_1"})
485
+ @hook_executor_constructor_hash_2 = hook_executor_constructor_hash.merge({:lifecycle_event => "lifecycle_event_2"})
486
+ @mock_hook_executor = mock
487
+ end
488
+
489
+ should "call both lifecycle events" do
490
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash_1).returns(@mock_hook_executor)
491
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash_2).returns(@mock_hook_executor)
492
+ @mock_hook_executor.expects(:execute).twice
493
+
494
+ @command_executor.execute_command(@command, @deployment_spec)
495
+ end
496
+
497
+ context "when the first script is forced to fail" do
498
+ setup do
499
+ HookExecutor.stubs(:new).with(@hook_executor_constructor_hash_1).raises("failed to create hook caommand")
500
+
501
+ end
502
+
503
+ should "calls lifecycle event 1 and fails but not 2" do
504
+ assert_raised_with_message('failed to create hook caommand') do
505
+ @command_executor.execute_command(@command, @deployment_spec)
506
+ end
507
+ HookExecutor.expects(:new).with(@hook_executor_constructor_hash_2).never
508
+ end
509
+ end
510
+ end
511
+ end
512
+ end
513
+ end