engineyard-serverside 2.8.0.pre4 → 2.8.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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/features/enable_maintenance/step_definitions/enable_maintenance_steps.rb +43 -0
  3. data/features/hook/running-a-deploy-hook.feature +277 -0
  4. data/features/hook/step_definitions/running-a-deploy-hook-steps.rb +200 -0
  5. data/features/step_definitions/app_steps.rb +10 -0
  6. data/features/step_definitions/command_steps.rb +8 -0
  7. data/features/step_definitions/server_steps.rb +14 -0
  8. data/features/step_definitions/version_steps.rb +5 -0
  9. data/features/support/env.rb +63 -0
  10. data/features/support/error_codes.rb +17 -0
  11. data/features/support/fs_helpers.rb +82 -0
  12. data/features/support/output_helpers.rb +7 -0
  13. data/features/support/runner.rb +41 -0
  14. data/features/version.feature +7 -0
  15. data/lib/engineyard-serverside/cli/app.rb +6 -0
  16. data/lib/engineyard-serverside/shell.rb +38 -10
  17. data/lib/engineyard-serverside/version.rb +1 -1
  18. data/spec/engineyard-serverside/callbacks/collection/combined_spec.rb +232 -0
  19. data/spec/engineyard-serverside/callbacks/collection/deploy_hooks_spec.rb +170 -0
  20. data/spec/engineyard-serverside/callbacks/collection/service_hooks/collection_spec.rb +171 -0
  21. data/spec/engineyard-serverside/callbacks/collection/service_hooks/combined_spec.rb +174 -0
  22. data/spec/engineyard-serverside/callbacks/collection/service_hooks_spec.rb +31 -0
  23. data/spec/engineyard-serverside/callbacks/collection_spec.rb +49 -0
  24. data/spec/engineyard-serverside/callbacks/distributor/remote_spec.rb +135 -0
  25. data/spec/engineyard-serverside/callbacks/distributor/viability_filter_spec.rb +208 -0
  26. data/spec/engineyard-serverside/callbacks/distributor_spec.rb +43 -0
  27. data/spec/engineyard-serverside/callbacks/executor/executable_spec.rb +386 -0
  28. data/spec/engineyard-serverside/callbacks/executor/ruby/context_spec.rb +538 -0
  29. data/spec/engineyard-serverside/callbacks/executor/ruby/executor_spec.rb +313 -0
  30. data/spec/engineyard-serverside/callbacks/executor/ruby_spec.rb +35 -0
  31. data/spec/engineyard-serverside/callbacks/executor_spec.rb +45 -0
  32. data/spec/engineyard-serverside/callbacks_spec.rb +31 -0
  33. data/spec/engineyard-serverside/cli/workflows/base_spec.rb +237 -0
  34. data/spec/engineyard-serverside/cli/workflows/calling_deploy_hooks_spec.rb +65 -0
  35. data/spec/engineyard-serverside/cli/workflows/deploying_applications_spec.rb +61 -0
  36. data/spec/engineyard-serverside/cli/workflows/disabling_maintenance_spec.rb +61 -0
  37. data/spec/engineyard-serverside/cli/workflows/enabling_maintenance_spec.rb +61 -0
  38. data/spec/engineyard-serverside/cli/workflows/helpers_spec.rb +64 -0
  39. data/spec/engineyard-serverside/cli/workflows/rolling_back_applications_spec.rb +61 -0
  40. data/spec/engineyard-serverside/cli/workflows/showing_maintenance_status_spec.rb +60 -0
  41. data/spec/engineyard-serverside/cli/workflows_spec.rb +87 -0
  42. data/spec/engineyard-serverside/dependency_manager/base_spec.rb +139 -0
  43. data/spec/engineyard-serverside/paths_spec.rb +820 -0
  44. data/spec/engineyard-serverside/propagator_spec.rb +56 -0
  45. data/spec/engineyard-serverside/server_spec.rb +390 -0
  46. data/spec/engineyard-serverside/shell/helpers_spec.rb +98 -0
  47. data/spec/engineyard-serverside/shell/yieldio_spec.rb +33 -0
  48. data/spec/engineyard-serverside/shell_spec.rb +543 -0
  49. data/spec/engineyard-serverside/slug/distributor_spec.rb +199 -0
  50. data/spec/engineyard-serverside/slug/enabler_spec.rb +191 -0
  51. data/spec/engineyard-serverside/slug/failure_handler_spec.rb +114 -0
  52. data/spec/engineyard-serverside/slug/finalizer_spec.rb +191 -0
  53. data/spec/engineyard-serverside/slug/generator_spec.rb +82 -0
  54. data/spec/engineyard-serverside/slug/migrator_spec.rb +137 -0
  55. data/spec/engineyard-serverside/slug/restarter_spec.rb +226 -0
  56. data/spec/engineyard-serverside/slug/source/updater_spec.rb +710 -0
  57. data/spec/engineyard-serverside/slug/source_spec.rb +40 -0
  58. data/spec/engineyard-serverside/source_spec.rb +171 -0
  59. data/spec/railway_spec.rb +130 -0
  60. data/spec/result/failure_spec.rb +113 -0
  61. data/spec/result/success_spec.rb +109 -0
  62. data/spec/result_spec.rb +23 -0
  63. data/spec/spec_helper.rb +3 -349
  64. metadata +182 -404
  65. data/spec/archive_deploy_spec.rb +0 -53
  66. data/spec/basic_deploy_spec.rb +0 -26
  67. data/spec/bundler_deploy_spec.rb +0 -160
  68. data/spec/configuration_spec.rb +0 -206
  69. data/spec/custom_deploy_spec.rb +0 -128
  70. data/spec/deploy_hook_spec.rb +0 -378
  71. data/spec/deprecation_spec.rb +0 -23
  72. data/spec/ey_yml_customized_deploy_spec.rb +0 -99
  73. data/spec/fixtures/gitrepo.tar.gz +0 -0
  74. data/spec/fixtures/invalid_hook.rb +0 -1
  75. data/spec/fixtures/lockfiles/0.9-no-bundler +0 -111
  76. data/spec/fixtures/lockfiles/0.9-with-bundler +0 -117
  77. data/spec/fixtures/lockfiles/1.0-no-bundler +0 -54
  78. data/spec/fixtures/lockfiles/1.0.0.rc.1-with-bundler +0 -162
  79. data/spec/fixtures/lockfiles/1.0.18-do_mysql +0 -88
  80. data/spec/fixtures/lockfiles/1.0.18-do_postgres +0 -79
  81. data/spec/fixtures/lockfiles/1.0.18-mysql +0 -43
  82. data/spec/fixtures/lockfiles/1.0.18-mysql2 +0 -43
  83. data/spec/fixtures/lockfiles/1.0.18-pg +0 -43
  84. data/spec/fixtures/lockfiles/1.0.6-no-bundler +0 -51
  85. data/spec/fixtures/lockfiles/1.0.6-with-any-bundler +0 -52
  86. data/spec/fixtures/lockfiles/1.0.6-with-bundler +0 -52
  87. data/spec/fixtures/lockfiles/1.15.1-no-bundler +0 -51
  88. data/spec/fixtures/lockfiles/1.3.1-rails-3.2.13 +0 -112
  89. data/spec/fixtures/lockfiles/not-a-lockfile +0 -1
  90. data/spec/fixtures/repos/assets_detected/Gemfile +0 -5
  91. data/spec/fixtures/repos/assets_detected/Gemfile.lock +0 -88
  92. data/spec/fixtures/repos/assets_detected/README +0 -1
  93. data/spec/fixtures/repos/assets_detected/Rakefile +0 -5
  94. data/spec/fixtures/repos/assets_detected/app/assets/empty +0 -0
  95. data/spec/fixtures/repos/assets_detected/config/application.rb +0 -5
  96. data/spec/fixtures/repos/assets_detected/config/ey.yml +0 -3
  97. data/spec/fixtures/repos/assets_disabled/Gemfile +0 -5
  98. data/spec/fixtures/repos/assets_disabled/Gemfile.lock +0 -88
  99. data/spec/fixtures/repos/assets_disabled/README +0 -1
  100. data/spec/fixtures/repos/assets_disabled/Rakefile +0 -6
  101. data/spec/fixtures/repos/assets_disabled/app/assets/empty +0 -0
  102. data/spec/fixtures/repos/assets_disabled/config/application.rb +0 -5
  103. data/spec/fixtures/repos/assets_disabled/config/ey.yml +0 -3
  104. data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile +0 -5
  105. data/spec/fixtures/repos/assets_disabled_in_ey_yml/Gemfile.lock +0 -88
  106. data/spec/fixtures/repos/assets_disabled_in_ey_yml/README +0 -1
  107. data/spec/fixtures/repos/assets_disabled_in_ey_yml/Rakefile +0 -6
  108. data/spec/fixtures/repos/assets_disabled_in_ey_yml/app/assets/empty +0 -0
  109. data/spec/fixtures/repos/assets_disabled_in_ey_yml/config/application.rb +0 -5
  110. data/spec/fixtures/repos/assets_disabled_in_ey_yml/config/ey.yml +0 -5
  111. data/spec/fixtures/repos/assets_disabled_utf8/Gemfile +0 -5
  112. data/spec/fixtures/repos/assets_disabled_utf8/Gemfile.lock +0 -88
  113. data/spec/fixtures/repos/assets_disabled_utf8/README +0 -3
  114. data/spec/fixtures/repos/assets_disabled_utf8/Rakefile +0 -5
  115. data/spec/fixtures/repos/assets_disabled_utf8/app/assets/empty +0 -0
  116. data/spec/fixtures/repos/assets_disabled_utf8/config/application.rb +0 -7
  117. data/spec/fixtures/repos/assets_disabled_utf8/config/ey.yml +0 -3
  118. data/spec/fixtures/repos/assets_enabled_all/Gemfile +0 -5
  119. data/spec/fixtures/repos/assets_enabled_all/Gemfile.lock +0 -88
  120. data/spec/fixtures/repos/assets_enabled_all/README +0 -1
  121. data/spec/fixtures/repos/assets_enabled_all/app/assets/empty +0 -0
  122. data/spec/fixtures/repos/assets_enabled_all/config/application.rb +0 -5
  123. data/spec/fixtures/repos/assets_enabled_all/config/ey.yml +0 -6
  124. data/spec/fixtures/repos/assets_enabled_all/script/assets +0 -5
  125. data/spec/fixtures/repos/assets_enabled_all/tmp/obstruction +0 -1
  126. data/spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile +0 -3
  127. data/spec/fixtures/repos/assets_enabled_in_ey_yml/Gemfile.lock +0 -10
  128. data/spec/fixtures/repos/assets_enabled_in_ey_yml/README +0 -1
  129. data/spec/fixtures/repos/assets_enabled_in_ey_yml/Rakefile +0 -8
  130. data/spec/fixtures/repos/assets_enabled_in_ey_yml/config/ey.yml +0 -4
  131. data/spec/fixtures/repos/assets_enabled_util_only/Gemfile +0 -5
  132. data/spec/fixtures/repos/assets_enabled_util_only/Gemfile.lock +0 -88
  133. data/spec/fixtures/repos/assets_enabled_util_only/README +0 -1
  134. data/spec/fixtures/repos/assets_enabled_util_only/Rakefile +0 -6
  135. data/spec/fixtures/repos/assets_enabled_util_only/app/assets/empty +0 -0
  136. data/spec/fixtures/repos/assets_enabled_util_only/config/application.rb +0 -5
  137. data/spec/fixtures/repos/assets_enabled_util_only/config/ey.yml +0 -6
  138. data/spec/fixtures/repos/assets_error/Gemfile +0 -5
  139. data/spec/fixtures/repos/assets_error/Gemfile.lock +0 -88
  140. data/spec/fixtures/repos/assets_error/README +0 -1
  141. data/spec/fixtures/repos/assets_error/Rakefile +0 -4
  142. data/spec/fixtures/repos/assets_error/app/assets/empty +0 -0
  143. data/spec/fixtures/repos/assets_error/config/application.rb +0 -5
  144. data/spec/fixtures/repos/assets_error/config/ey.yml +0 -4
  145. data/spec/fixtures/repos/assets_in_hook/Gemfile +0 -5
  146. data/spec/fixtures/repos/assets_in_hook/Gemfile.lock +0 -88
  147. data/spec/fixtures/repos/assets_in_hook/README +0 -2
  148. data/spec/fixtures/repos/assets_in_hook/Rakefile +0 -5
  149. data/spec/fixtures/repos/assets_in_hook/app/assets/empty +0 -0
  150. data/spec/fixtures/repos/assets_in_hook/config/application.rb +0 -5
  151. data/spec/fixtures/repos/assets_in_hook/config/ey.yml +0 -3
  152. data/spec/fixtures/repos/assets_in_hook/deploy/before_compile_assets.rb +0 -2
  153. data/spec/fixtures/repos/bundle_fails/Gemfile +0 -1
  154. data/spec/fixtures/repos/bundle_fails/README +0 -1
  155. data/spec/fixtures/repos/bundle_fails/deploy/after_bundle.rb +0 -1
  156. data/spec/fixtures/repos/bundler_disabled/Gemfile +0 -4
  157. data/spec/fixtures/repos/bundler_disabled/Gemfile.lock +0 -12
  158. data/spec/fixtures/repos/bundler_disabled/README +0 -1
  159. data/spec/fixtures/repos/bundler_disabled/config/ey.yml +0 -2
  160. data/spec/fixtures/repos/bundler_disabled/deploy/after_bundle.rb +0 -1
  161. data/spec/fixtures/repos/bundler_disabled/deploy/before_bundle.rb +0 -1
  162. data/spec/fixtures/repos/bundler_old/Gemfile +0 -5
  163. data/spec/fixtures/repos/bundler_old/Gemfile.lock +0 -15
  164. data/spec/fixtures/repos/bundler_old/README +0 -1
  165. data/spec/fixtures/repos/default/Gemfile +0 -4
  166. data/spec/fixtures/repos/default/Gemfile.lock +0 -12
  167. data/spec/fixtures/repos/default/README +0 -5
  168. data/spec/fixtures/repos/default/ey.yml +0 -3
  169. data/spec/fixtures/repos/executable_hooks/README +0 -1
  170. data/spec/fixtures/repos/executable_hooks/deploy/before_restart +0 -72
  171. data/spec/fixtures/repos/executable_hooks_not_executable/README +0 -3
  172. data/spec/fixtures/repos/executable_hooks_not_executable/deploy/before_restart +0 -3
  173. data/spec/fixtures/repos/ey_yml/Gemfile +0 -4
  174. data/spec/fixtures/repos/ey_yml/Gemfile.lock +0 -12
  175. data/spec/fixtures/repos/ey_yml/README +0 -1
  176. data/spec/fixtures/repos/ey_yml/config/ey.yml +0 -18
  177. data/spec/fixtures/repos/ey_yml/deploy/before_migrate.rb +0 -6
  178. data/spec/fixtures/repos/ey_yml_alt/Gemfile +0 -4
  179. data/spec/fixtures/repos/ey_yml_alt/Gemfile.lock +0 -12
  180. data/spec/fixtures/repos/ey_yml_alt/README +0 -1
  181. data/spec/fixtures/repos/ey_yml_alt/deploy/before_migrate.rb +0 -6
  182. data/spec/fixtures/repos/ey_yml_alt/ey.yml +0 -12
  183. data/spec/fixtures/repos/hook_fails/README +0 -1
  184. data/spec/fixtures/repos/hook_fails/deploy/before_deploy.rb +0 -1
  185. data/spec/fixtures/repos/hooks/README +0 -1
  186. data/spec/fixtures/repos/hooks/deploy/after_bundle.rb +0 -1
  187. data/spec/fixtures/repos/hooks/deploy/after_compile_assets.rb +0 -1
  188. data/spec/fixtures/repos/hooks/deploy/after_deploy.rb +0 -1
  189. data/spec/fixtures/repos/hooks/deploy/after_migrate.rb +0 -1
  190. data/spec/fixtures/repos/hooks/deploy/after_restart.rb +0 -1
  191. data/spec/fixtures/repos/hooks/deploy/after_symlink.rb +0 -1
  192. data/spec/fixtures/repos/hooks/deploy/before_bundle.rb +0 -1
  193. data/spec/fixtures/repos/hooks/deploy/before_compile_assets.rb +0 -1
  194. data/spec/fixtures/repos/hooks/deploy/before_deploy.rb +0 -1
  195. data/spec/fixtures/repos/hooks/deploy/before_migrate.rb +0 -1
  196. data/spec/fixtures/repos/hooks/deploy/before_restart.rb +0 -1
  197. data/spec/fixtures/repos/hooks/deploy/before_symlink.rb +0 -1
  198. data/spec/fixtures/repos/multi_dep_manager/README +0 -1
  199. data/spec/fixtures/repos/multi_dep_manager/composer.json +0 -5
  200. data/spec/fixtures/repos/multi_dep_manager/composer.lock +0 -462
  201. data/spec/fixtures/repos/multi_dep_manager/package.json +0 -7
  202. data/spec/fixtures/repos/multi_dep_manager/public/index.php +0 -4
  203. data/spec/fixtures/repos/no_ey_config/Gemfile +0 -3
  204. data/spec/fixtures/repos/no_ey_config/Gemfile.lock +0 -10
  205. data/spec/fixtures/repos/no_ey_config/README +0 -1
  206. data/spec/fixtures/repos/no_ey_config/ey.yml +0 -3
  207. data/spec/fixtures/repos/no_ey_config_no_warning/Gemfile +0 -3
  208. data/spec/fixtures/repos/no_ey_config_no_warning/Gemfile.lock +0 -10
  209. data/spec/fixtures/repos/no_ey_config_no_warning/README +0 -1
  210. data/spec/fixtures/repos/no_ey_config_no_warning/ey.yml +0 -5
  211. data/spec/fixtures/repos/no_gemfile_lock/Gemfile +0 -4
  212. data/spec/fixtures/repos/no_gemfile_lock/README +0 -1
  213. data/spec/fixtures/repos/no_gemfile_lock/ey.yml +0 -3
  214. data/spec/fixtures/repos/nodejs/README +0 -1
  215. data/spec/fixtures/repos/nodejs/package.json +0 -7
  216. data/spec/fixtures/repos/not_bundled/README +0 -1
  217. data/spec/fixtures/repos/npm_disabled/README +0 -1
  218. data/spec/fixtures/repos/npm_disabled/config/ey.yml +0 -2
  219. data/spec/fixtures/repos/npm_disabled/package.json +0 -7
  220. data/spec/fixtures/repos/php_composer_disabled/README +0 -1
  221. data/spec/fixtures/repos/php_composer_disabled/composer.json +0 -5
  222. data/spec/fixtures/repos/php_composer_disabled/composer.lock +0 -462
  223. data/spec/fixtures/repos/php_composer_disabled/config/ey.yml +0 -2
  224. data/spec/fixtures/repos/php_composer_disabled/public/index.php +0 -4
  225. data/spec/fixtures/repos/php_composer_lock/README +0 -1
  226. data/spec/fixtures/repos/php_composer_lock/composer.json +0 -5
  227. data/spec/fixtures/repos/php_composer_lock/composer.lock +0 -462
  228. data/spec/fixtures/repos/php_composer_lock/public/index.php +0 -4
  229. data/spec/fixtures/repos/php_no_composer_lock/README +0 -1
  230. data/spec/fixtures/repos/php_no_composer_lock/composer.json +0 -21
  231. data/spec/fixtures/repos/php_no_composer_lock/public/index.php +0 -4
  232. data/spec/fixtures/repos/public_system/Gemfile +0 -4
  233. data/spec/fixtures/repos/public_system/Gemfile.lock +0 -12
  234. data/spec/fixtures/repos/public_system/README +0 -5
  235. data/spec/fixtures/repos/public_system/ey.yml +0 -3
  236. data/spec/fixtures/repos/public_system/public/system/cant_touch_this.txt +0 -3
  237. data/spec/fixtures/repos/sqlite3/Gemfile +0 -4
  238. data/spec/fixtures/repos/sqlite3/Gemfile.lock +0 -89
  239. data/spec/fixtures/repos/sqlite3/README +0 -1
  240. data/spec/fixtures/retwisj.war +0 -0
  241. data/spec/fixtures/valid_hook.rb +0 -1
  242. data/spec/git_strategy_spec.rb +0 -34
  243. data/spec/lockfile_parser_spec.rb +0 -126
  244. data/spec/maintenance_spec.rb +0 -44
  245. data/spec/multi_dependency_manager_spec.rb +0 -25
  246. data/spec/nodejs_deploy_spec.rb +0 -30
  247. data/spec/php_deploy_spec.rb +0 -81
  248. data/spec/platform_configure_spec.rb +0 -61
  249. data/spec/rails31_deploy_spec.rb +0 -172
  250. data/spec/restart_spec.rb +0 -43
  251. data/spec/rollback_spec.rb +0 -87
  252. data/spec/server_spec.rb +0 -70
  253. data/spec/services_deploy_spec.rb +0 -165
  254. data/spec/shell_spec.rb +0 -57
  255. data/spec/source/archive_spec.rb +0 -33
  256. data/spec/source/git_spec.rb +0 -44
  257. data/spec/sqlite3_deploy_spec.rb +0 -38
  258. data/spec/support/integration.rb +0 -103
  259. data/spec/support/source_doubles.rb +0 -28
  260. data/spec/support/timecop.rb +0 -5
  261. data/spec/symlink_spec.rb +0 -15
@@ -0,0 +1,386 @@
1
+ require 'spec_helper'
2
+ require 'escape'
3
+
4
+ require 'result'
5
+
6
+ require 'engineyard-serverside/callbacks/executor/executable'
7
+
8
+ module EY
9
+ module Serverside
10
+ module Callbacks
11
+ module Executor
12
+
13
+ describe Executable do
14
+ let(:config) {Object.new}
15
+ let(:shell) {Object.new}
16
+ let(:paths) {Object.new}
17
+ let(:hook) {Object.new}
18
+ let(:short_name) {'hook'}
19
+ let(:active_release_path) {'/path/to/the/active/release'}
20
+ let(:hook_path) {'/path/to/the/dang/hook'}
21
+ let(:account_name) {'george'}
22
+ let(:app) {'tacoma'}
23
+ let(:env_name) {'gracie'}
24
+ let(:framework_env) {'sausages'}
25
+ let(:current_roles) {['hamlet', 'ophelia']}
26
+ let(:current_name) {nil}
27
+ let(:config_json) {'a big ol hash'}
28
+ let(:verbose) {false}
29
+ let(:execution_success) {true}
30
+ let(:hook_string) {'hooky'}
31
+
32
+ let(:executor) {described_class.new(config, shell, hook)}
33
+
34
+ before(:each) do
35
+ allow(hook).to receive(:path).and_return(hook_path)
36
+ allow(hook).to receive(:short_name).and_return(short_name)
37
+ allow(hook).to receive(:to_s).and_return(hook_string)
38
+ allow(hook).
39
+ to receive(:respond_to?).
40
+ with(:service_name).
41
+ and_return(false)
42
+
43
+ allow(shell).to receive(:info)
44
+ allow(shell).to receive(:fatal)
45
+ allow(shell).to receive(:warning)
46
+
47
+ allow(config).to receive(:paths).and_return(paths)
48
+ allow(config).to receive(:current_roles).and_return(current_roles)
49
+ allow(config).to receive(:account_name).and_return(account_name)
50
+ allow(config).to receive(:app).and_return(app)
51
+ allow(config).to receive(:environment_name).and_return(env_name)
52
+ allow(config).to receive(:verbose).and_return(verbose)
53
+ allow(config).to receive(:current_name).and_return(current_name)
54
+ allow(config).to receive(:framework_env).and_return(framework_env)
55
+ allow(config).to receive(:to_json).and_return(config_json)
56
+ allow(config).
57
+ to receive(:framework_envs).
58
+ and_return("RACK_ENV=#{framework_env} RAILS_ENV=#{framework_env}")
59
+
60
+
61
+ allow(paths).to receive(:active_release).and_return(active_release_path)
62
+ allow(hook_path).to receive(:executable?).and_return(true)
63
+
64
+ # This is a wee bit dirty, but the easiest way to test our actual code
65
+ # here is to stub out the included Runner interface.
66
+ allow(executor).to receive(:run) do |cmd|
67
+ EY::Serverside::Spawner::Result.new(cmd, execution_success, cmd, nil)
68
+ end
69
+
70
+ # We also need to stub out the #abort method, as we don't need the
71
+ # test suite to just up and stop running when we test executor failure
72
+ # modes.
73
+ allow(executor).to receive(:abort)
74
+ end
75
+
76
+ it 'is a Railway' do
77
+ expect(executor).to be_a(Railway)
78
+ end
79
+
80
+ it 'knows how to spawn CLI processes' do
81
+ expect(executor).to be_a(Runner)
82
+ end
83
+
84
+ it 'has the exact steps for executing a Ruby hook' do
85
+ steps = described_class.steps.map {|s| s[:name]}
86
+
87
+ expect(steps).to eql(
88
+ [
89
+ :validate_hook,
90
+ :populate_environment,
91
+ :calculate_wrapper,
92
+ :run_hook
93
+ ]
94
+ )
95
+ end
96
+
97
+ describe '#validate_hook' do
98
+ let(:input) {
99
+ {}
100
+ }
101
+
102
+ let(:result) {executor.validate_hook}
103
+
104
+ context 'when the hook has the executable bit' do
105
+ before(:each) do
106
+ allow(hook_path).to receive(:executable?).and_return(true)
107
+ end
108
+
109
+ it 'is a Success' do
110
+ expect(result).to be_a(Result::Success)
111
+ end
112
+
113
+ it 'does not alter the input' do
114
+ expect(result.value).to eql(input)
115
+ end
116
+ end
117
+
118
+ context 'when the hook lacks the executable bit' do
119
+ before(:each) do
120
+ allow(hook_path).to receive(:executable?).and_return(false)
121
+ end
122
+
123
+ it 'is a Failure' do
124
+ expect(result).to be_a(Result::Failure)
125
+ end
126
+
127
+ it 'contains a reason for the failure' do
128
+ expect(result.error[:reason]).to eql(:not_executable)
129
+ end
130
+ end
131
+ end
132
+
133
+ describe '#populate_environment' do
134
+ let(:input) {{}}
135
+
136
+ let(:result) {executor.populate_environment(input)}
137
+ let(:result_env) {result.value[:environment]}
138
+
139
+ it 'is a Success' do
140
+ expect(result).to be_a(Result::Success)
141
+ end
142
+
143
+ it 'adds the environment to the input' do
144
+ expect(result_env).to be_a(String)
145
+ end
146
+
147
+ it 'includes the account name in the environment' do
148
+ escaped = Escape.shell_command([account_name])
149
+
150
+ expect(result_env).
151
+ to match(%r{EY_DEPLOY_ACCOUNT_NAME=#{escaped}})
152
+ end
153
+
154
+ it 'includes the application in the environment' do
155
+ escaped = Escape.shell_command([app])
156
+
157
+ expect(result_env).
158
+ to match(%{EY_DEPLOY_APP=#{escaped}})
159
+ end
160
+
161
+ it 'includes the JSON representation of the config in the environment' do
162
+ escaped = Escape.shell_command([config_json])
163
+
164
+ expect(result_env).
165
+ to match(%r{EY_DEPLOY_CONFIG=#{escaped}})
166
+ end
167
+
168
+ it 'includes all of the current roles in the environment' do
169
+ expect(result_env).
170
+ to match(%r{EY_DEPLOY_CURRENT_ROLES='#{current_roles.join(' ')}'})
171
+ end
172
+
173
+ context 'when the server is named' do
174
+ let(:current_name) {'frankie'}
175
+ let(:escaped) {Escape.shell_command([current_name])}
176
+
177
+ it 'includes the current server name' do
178
+ expect(result_env).
179
+ to match(%r{EY_DEPLOY_CURRENT_NAME=#{escaped}})
180
+ end
181
+ end
182
+
183
+ context 'when the server is unnamed' do
184
+ let(:current_name) {nil}
185
+
186
+ it 'omits the current server name' do
187
+ expect(result_env).
188
+ not_to match(%r{EY_DEPLOY_CURRENT_NAME})
189
+ end
190
+ end
191
+
192
+ it 'includes the environment name in the environment' do
193
+ escaped = Escape.shell_command([env_name])
194
+
195
+ expect(result_env).
196
+ to match(%r{EY_DEPLOY_ENVIRONMENT_NAME=#{escaped}})
197
+ end
198
+
199
+ it 'includes the framwork env in the environment' do
200
+ escaped = Escape.shell_command([framework_env])
201
+
202
+ expect(result_env).
203
+ to match(%r{EY_DEPLOY_FRAMEWORK_ENV=#{escaped}})
204
+ end
205
+
206
+ it 'includes the release path in the environment' do
207
+ escaped = Escape.shell_command([active_release_path])
208
+
209
+ expect(result_env).
210
+ to match(%r{EY_DEPLOY_RELEASE_PATH=#{escaped}})
211
+ end
212
+
213
+ context 'with verbosity configured' do
214
+ let(:verbose) {true}
215
+
216
+ it 'enables verbosity in the environment' do
217
+ expect(result.value[:environment]).
218
+ to match(%r{EY_DEPLOY_VERBOSE=1})
219
+ end
220
+ end
221
+
222
+ context 'without verbosity configured' do
223
+ let(:verbose) {false}
224
+
225
+ it 'disables verbosity in the environment' do
226
+ expect(result.value[:environment]).
227
+ to match(%r{EY_DEPLOY_VERBOSE=0})
228
+ end
229
+ end
230
+
231
+ context 'when any of the values involved are nil' do
232
+ let(:account_name) {nil}
233
+ let(:app) {nil}
234
+ let(:config_json) {nil}
235
+ let(:env_name) {nil}
236
+
237
+ it 'omits those env vars' do
238
+ affected = ['ACCOUNT_NAME', 'APP', 'CONFIG', 'ENVIRONMENT_NAME']
239
+
240
+ affected.each do |var|
241
+ expect(result_env).not_to match(%r{EY_DEPLOY_#{var}})
242
+ end
243
+ end
244
+
245
+ end
246
+
247
+ end
248
+
249
+ describe '#calculate_wrapper' do
250
+ let(:input) {{}}
251
+
252
+ let(:result) {executor.calculate_wrapper(input)}
253
+
254
+ it 'is a Success' do
255
+ expect(result).to be_a(Result::Success)
256
+ end
257
+
258
+ it 'adds a wrapper to the input' do
259
+ expect(result.value[:wrapper]).not_to be_nil
260
+ end
261
+
262
+ context 'when dealing with a service hook' do
263
+ before(:each) do
264
+ allow(hook).
265
+ to receive(:respond_to?).
266
+ with(:service_name).
267
+ and_return(true)
268
+ end
269
+
270
+ it 'wraps the service hook executor' do
271
+ expect(result.value[:wrapper]).to eql(About.service_hook_executor)
272
+ end
273
+ end
274
+
275
+ context 'when dealing with an app hook' do
276
+ before(:each) do
277
+ allow(hook).
278
+ to receive(:respond_to?).
279
+ with(:service_name).
280
+ and_return(false)
281
+ end
282
+
283
+ it 'wraps the app hook executor' do
284
+ expect(result.value[:wrapper]).to eql(About.hook_executor)
285
+ end
286
+ end
287
+ end
288
+
289
+ describe '#run_hook' do
290
+ let(:dummy_env) {'i am an environment'}
291
+ let(:wrapper) {'candy-bar'}
292
+ let(:input) {
293
+ {
294
+ :wrapper => wrapper,
295
+ :environment => dummy_env
296
+ }
297
+ }
298
+
299
+ let(:result) {executor.run_hook(input)}
300
+
301
+ it 'runs the proper command' do
302
+ expect(executor).
303
+ to receive(:run).
304
+ with(
305
+ "#{dummy_env} #{config.framework_envs} #{wrapper} #{short_name}"
306
+ )
307
+
308
+ result
309
+ end
310
+
311
+ context 'when the execution succeeds' do
312
+ let(:execution_success) {true}
313
+
314
+ it 'is a Success' do
315
+ expect(result).to be_a(Result::Success)
316
+ end
317
+
318
+ it 'does not alter the input' do
319
+ expect(result.value).to eql(input)
320
+ end
321
+ end
322
+
323
+ context 'when the execution fails' do
324
+ let(:execution_success) {false}
325
+
326
+ it 'is a Failure' do
327
+ expect(result).to be_a(Result::Failure)
328
+ end
329
+
330
+ it 'has exeuction failure as its reason' do
331
+ expect(result.error[:reason]).to eql(:execution_failed)
332
+ end
333
+ end
334
+ end
335
+
336
+ describe '#handle_failure' do
337
+ let(:reason) {nil}
338
+ let(:error) {
339
+ {
340
+ :reason => reason
341
+ }
342
+ }
343
+
344
+ let(:result) {executor.handle_failure(error)}
345
+
346
+ context 'when the hook is not actually executable' do
347
+ let(:reason) {:not_executable}
348
+
349
+ it 'does nothing and returns true' do
350
+ expect(result).to eql(true)
351
+ end
352
+ end
353
+
354
+ context 'when execution of the hook fails' do
355
+ let(:reason) {:execution_failed}
356
+
357
+ it 'aborts with a message about the execution failure' do
358
+ expect(executor).
359
+ to receive(:abort).
360
+ with(
361
+ "*** [Error] Hook failed to exit cleanly: #{hook_path} ***\n"
362
+ )
363
+
364
+ result
365
+ end
366
+ end
367
+
368
+ context 'when an otherwise unexpected error occurs' do
369
+ let(:reason) {nil}
370
+
371
+ it 'aborts with a message about the unknown error' do
372
+ expect(executor).
373
+ to receive(:abort).
374
+ with("*** [Error] An unknown error occurred for hook: #{hook_path} ***\n")
375
+
376
+ result
377
+ end
378
+ end
379
+ end
380
+
381
+ end
382
+
383
+ end
384
+ end
385
+ end
386
+ end
@@ -0,0 +1,538 @@
1
+ require 'spec_helper'
2
+
3
+ require 'escape'
4
+
5
+ require 'engineyard-serverside/callbacks/executor/ruby/context'
6
+
7
+ module EY
8
+ module Serverside
9
+ module Callbacks
10
+ module Executor
11
+ module Ruby
12
+
13
+ describe Context do
14
+ let(:config) {
15
+ Class.new do
16
+ def two_minus_one
17
+ 1
18
+ end
19
+ end.new
20
+ }
21
+
22
+ let(:shell) {Object.new}
23
+ let(:paths) {Object.new}
24
+ let(:hook) {Object.new}
25
+ let(:hook_path) {'/path/to/the/dang/hook.rb'}
26
+ let(:current_roles) {['hamlet', 'ophelia']}
27
+ let(:node) {Object.new}
28
+ let(:active_release_path) {'/path/to/the/release'}
29
+ let(:execution_success) {true}
30
+
31
+ let(:context) {described_class.new(config, shell, hook)}
32
+
33
+ before(:each) do
34
+ allow(hook).to receive(:path).and_return(hook_path)
35
+
36
+ allow(shell).to receive(:info)
37
+ allow(shell).to receive(:fatal)
38
+ allow(shell).to receive(:warning)
39
+ allow(shell).to receive(:logged_system) do |cmd|
40
+ EY::Serverside::Spawner::Result.new(
41
+ cmd,
42
+ execution_success,
43
+ cmd,
44
+ nil
45
+ )
46
+ end
47
+
48
+ allow(config).to receive(:paths).and_return(paths)
49
+ allow(config).to receive(:set_framework_envs)
50
+ allow(config).to receive(:node).and_return(node)
51
+ allow(config).to receive(:current_roles).and_return(current_roles)
52
+
53
+ allow(paths).
54
+ to receive(:active_release).
55
+ and_return(active_release_path)
56
+ end
57
+
58
+ describe '#inspect' do
59
+ let(:result) {context.inspect}
60
+
61
+ it 'is a string' do
62
+ expect(result).to be_a(String)
63
+ end
64
+
65
+ it 'includes the context namespace path' do
66
+ expect(result).to match(%r{Callbacks::Executor::Ruby::Context})
67
+ end
68
+
69
+ it 'includes the path to the hook' do
70
+ expect(result).to match(%{#{hook_path.inspect}})
71
+ end
72
+
73
+ it 'looks like a typical inspect result' do
74
+ expect(result).to match(%{^#<.*>$})
75
+ end
76
+ end
77
+
78
+ describe '#config' do
79
+ it 'is the configuration object for the context' do
80
+ expect(context.config).to eql(context.config)
81
+ end
82
+ end
83
+
84
+ describe '#method_missing' do
85
+ context 'for config methods' do
86
+ let(:result) {context.two_minus_one}
87
+
88
+ it 'warns about deprecated missing_method reliance' do
89
+ expect(shell).to receive(:warning).with("Use of `two_minus_one` (via method_missing) is deprecated in favor of `config.two_minus_one` for improved error messages and compatibility.\n\tin #{hook_path}")
90
+
91
+ result
92
+ end
93
+
94
+ it 'passes the call along to config' do
95
+ expect(config).to receive(:two_minus_one).and_return(3)
96
+
97
+ expect(result).to eql(3)
98
+ end
99
+ end
100
+
101
+ context 'for non-config methods' do
102
+ let(:result) {context.two_minus_two}
103
+
104
+ it 'eventually raises an error' do
105
+ expect {result}.to raise_error
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ describe '#respond_to?' do
112
+ let(:meth) {:class}
113
+
114
+ let(:result) {context.respond_to?(meth)}
115
+
116
+ context 'when given a config method' do
117
+ let(:meth) {:two_minus_one}
118
+
119
+ it 'is true' do
120
+ expect(result).to eql(true)
121
+ end
122
+ end
123
+
124
+ context 'when given a non-config method' do
125
+ context 'that context knows how to handle' do
126
+ let(:meth) {:run}
127
+
128
+ it 'is true' do
129
+ expect(result).to eql(true)
130
+ end
131
+ end
132
+
133
+ context 'that context does not know how to handle' do
134
+ let(:meth) {:walk}
135
+
136
+ it 'is false' do
137
+ expect(result).to eql(false)
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ describe '#run' do
144
+ let(:cmd) {'touch yournose'}
145
+ let(:result) {context.run(cmd)}
146
+
147
+ it 'runs the wrapped command via the shell with logging' do
148
+ expect(shell).
149
+ to receive(:logged_system).
150
+ with("sh -l -c 'touch yournose'")
151
+
152
+ result
153
+ end
154
+
155
+ context 'when the command succeeds' do
156
+ let(:execution_success) {true}
157
+
158
+ it 'is false' do
159
+ expect(result).to eql(true)
160
+ end
161
+ end
162
+
163
+ context 'when the command fails' do
164
+ let(:execution_success) {false}
165
+
166
+ it 'is false' do
167
+ expect(result).to eql(false)
168
+ end
169
+ end
170
+ end
171
+
172
+ describe '#run!' do
173
+ let(:cmd) {'touch yourtoes'}
174
+ let(:result) {context.run!(cmd)}
175
+
176
+ it 'runs the command' do
177
+ expect(context).to receive(:run).with(cmd).and_return(true)
178
+
179
+ result
180
+ end
181
+
182
+ context 'when the command succeeds' do
183
+ let(:execution_success) {true}
184
+
185
+ it 'is true' do
186
+ expect(result).to eql(true)
187
+ end
188
+ end
189
+
190
+ context 'when the command fails' do
191
+ let(:execution_success) {false}
192
+
193
+ it 'raises an error' do
194
+ expect {result}.to raise_error("run!: Command failed. #{cmd}")
195
+ end
196
+ end
197
+ end
198
+
199
+ describe '#sudo' do
200
+ let(:cmd) {'touch yournose'}
201
+ let(:result) {context.sudo(cmd)}
202
+
203
+ it 'runs the sudo-wrapped command via the shell with logging' do
204
+ expect(shell).
205
+ to receive(:logged_system).
206
+ with("sudo sh -l -c 'touch yournose'")
207
+
208
+ result
209
+ end
210
+
211
+ context 'when the command succeeds' do
212
+ let(:execution_success) {true}
213
+
214
+ it 'is false' do
215
+ expect(result).to eql(true)
216
+ end
217
+ end
218
+
219
+ context 'when the command fails' do
220
+ let(:execution_success) {false}
221
+
222
+ it 'is false' do
223
+ expect(result).to eql(false)
224
+ end
225
+ end
226
+ end
227
+
228
+
229
+ describe '#sudo!' do
230
+ let(:cmd) {'touch yourtoes'}
231
+ let(:result) {context.sudo!(cmd)}
232
+
233
+ it 'sudo runs the command' do
234
+ expect(context).to receive(:sudo).with(cmd).and_return(true)
235
+
236
+ result
237
+ end
238
+
239
+ context 'when the command succeeds' do
240
+ let(:execution_success) {true}
241
+
242
+ it 'is true' do
243
+ expect(result).to eql(true)
244
+ end
245
+ end
246
+
247
+ context 'when the command fails' do
248
+ let(:execution_success) {false}
249
+
250
+ it 'raises an error' do
251
+ expect {result}.to raise_error("sudo!: Command failed. #{cmd}")
252
+ end
253
+ end
254
+ end
255
+
256
+ describe '#on_app_master' do
257
+ let(:dummy) {Object.new}
258
+ let(:result) {context.on_app_master {dummy.process}}
259
+
260
+ before(:each) do
261
+ allow(dummy).to receive(:process)
262
+ end
263
+
264
+ context 'on a solo instance' do
265
+ let(:current_roles) {['solo']}
266
+
267
+ it 'runs the given block' do
268
+ expect(dummy).to receive(:process)
269
+
270
+ result
271
+ end
272
+ end
273
+
274
+ context 'on an app master instance' do
275
+ let(:current_roles) {['app_master']}
276
+
277
+ it 'runs the given block' do
278
+ expect(dummy).to receive(:process)
279
+
280
+ result
281
+ end
282
+ end
283
+
284
+ context 'on an app instance' do
285
+ let(:current_roles) {['app']}
286
+
287
+ it 'skips the given block' do
288
+ expect(dummy).not_to receive(:process)
289
+
290
+ result
291
+ end
292
+ end
293
+
294
+ context 'on a util instance' do
295
+ let(:current_roles) {['util']}
296
+
297
+ it 'skips the given block' do
298
+ expect(dummy).not_to receive(:process)
299
+
300
+ result
301
+ end
302
+ end
303
+
304
+ context 'on a database master instance' do
305
+ let(:current_roles) {['db_master']}
306
+
307
+ it 'skips the given block' do
308
+ expect(dummy).not_to receive(:process)
309
+
310
+ result
311
+ end
312
+ end
313
+
314
+ context 'on a database replicant instance' do
315
+ let(:current_roles) {['db_slave']}
316
+
317
+ it 'skips the given block' do
318
+ expect(dummy).not_to receive(:process)
319
+
320
+ result
321
+ end
322
+ end
323
+ end
324
+
325
+ describe '#on_app_servers' do
326
+ let(:dummy) {Object.new}
327
+ let(:result) {context.on_app_servers {dummy.process}}
328
+
329
+ before(:each) do
330
+ allow(dummy).to receive(:process)
331
+ end
332
+
333
+ context 'on a solo instance' do
334
+ let(:current_roles) {['solo']}
335
+
336
+ it 'runs the given block' do
337
+ expect(dummy).to receive(:process)
338
+
339
+ result
340
+ end
341
+ end
342
+
343
+ context 'on an app master instance' do
344
+ let(:current_roles) {['app_master']}
345
+
346
+ it 'runs the given block' do
347
+ expect(dummy).to receive(:process)
348
+
349
+ result
350
+ end
351
+ end
352
+
353
+ context 'on an app instance' do
354
+ let(:current_roles) {['app']}
355
+
356
+ it 'runs the given block' do
357
+ expect(dummy).to receive(:process)
358
+
359
+ result
360
+ end
361
+ end
362
+
363
+ context 'on a util instance' do
364
+ let(:current_roles) {['util']}
365
+
366
+ it 'skips the given block' do
367
+ expect(dummy).not_to receive(:process)
368
+
369
+ result
370
+ end
371
+ end
372
+
373
+ context 'on a database master instance' do
374
+ let(:current_roles) {['db_master']}
375
+
376
+ it 'skips the given block' do
377
+ expect(dummy).not_to receive(:process)
378
+
379
+ result
380
+ end
381
+ end
382
+
383
+ context 'on a database replicant instance' do
384
+ let(:current_roles) {['db_slave']}
385
+
386
+ it 'skips the given block' do
387
+ expect(dummy).not_to receive(:process)
388
+
389
+ result
390
+ end
391
+ end
392
+ end
393
+
394
+ describe '#on_app_servers_and_utilities' do
395
+ let(:dummy) {Object.new}
396
+ let(:result) {context.on_app_servers_and_utilities {dummy.process}}
397
+
398
+ before(:each) do
399
+ allow(dummy).to receive(:process)
400
+ end
401
+
402
+ context 'on a solo instance' do
403
+ let(:current_roles) {['solo']}
404
+
405
+ it 'runs the given block' do
406
+ expect(dummy).to receive(:process)
407
+
408
+ result
409
+ end
410
+ end
411
+
412
+ context 'on an app master instance' do
413
+ let(:current_roles) {['app_master']}
414
+
415
+ it 'runs the given block' do
416
+ expect(dummy).to receive(:process)
417
+
418
+ result
419
+ end
420
+ end
421
+
422
+ context 'on an app instance' do
423
+ let(:current_roles) {['app']}
424
+
425
+ it 'runs the given block' do
426
+ expect(dummy).to receive(:process)
427
+
428
+ result
429
+ end
430
+ end
431
+
432
+ context 'on a util instance' do
433
+ let(:current_roles) {['util']}
434
+
435
+ it 'runs the given block' do
436
+ expect(dummy).to receive(:process)
437
+
438
+ result
439
+ end
440
+ end
441
+
442
+ context 'on a database master instance' do
443
+ let(:current_roles) {['db_master']}
444
+
445
+ it 'skips the given block' do
446
+ expect(dummy).not_to receive(:process)
447
+
448
+ result
449
+ end
450
+ end
451
+
452
+ context 'on a database replicant instance' do
453
+ let(:current_roles) {['db_slave']}
454
+
455
+ it 'skips the given block' do
456
+ expect(dummy).not_to receive(:process)
457
+
458
+ result
459
+ end
460
+ end
461
+ end
462
+
463
+ describe '#on_utilities' do
464
+ let(:dummy) {Object.new}
465
+ let(:result) {context.on_utilities {dummy.process}}
466
+
467
+ before(:each) do
468
+ allow(dummy).to receive(:process)
469
+ end
470
+
471
+ context 'on a solo instance' do
472
+ let(:current_roles) {['solo']}
473
+
474
+ it 'skips the given block' do
475
+ expect(dummy).not_to receive(:process)
476
+
477
+ result
478
+ end
479
+ end
480
+
481
+ context 'on an app master instance' do
482
+ let(:current_roles) {['app_master']}
483
+
484
+ it 'skips the given block' do
485
+ expect(dummy).not_to receive(:process)
486
+
487
+ result
488
+ end
489
+ end
490
+
491
+ context 'on an app instance' do
492
+ let(:current_roles) {['app']}
493
+
494
+ it 'skips the given block' do
495
+ expect(dummy).not_to receive(:process)
496
+
497
+ result
498
+ end
499
+ end
500
+
501
+ context 'on a util instance' do
502
+ let(:current_roles) {['util']}
503
+
504
+ it 'runs the given block' do
505
+ expect(dummy).to receive(:process)
506
+
507
+ result
508
+ end
509
+ end
510
+
511
+ context 'on a database master instance' do
512
+ let(:current_roles) {['db_master']}
513
+
514
+ it 'skips the given block' do
515
+ expect(dummy).not_to receive(:process)
516
+
517
+ result
518
+ end
519
+ end
520
+
521
+ context 'on a database replicant instance' do
522
+ let(:current_roles) {['db_slave']}
523
+
524
+ it 'skips the given block' do
525
+ expect(dummy).not_to receive(:process)
526
+
527
+ result
528
+ end
529
+ end
530
+ end
531
+
532
+ end
533
+
534
+ end
535
+ end
536
+ end
537
+ end
538
+ end