aws-codedeploy-agent 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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