engineyard 1.4.29 → 1.7.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/README.rdoc +139 -4
  2. data/bin/ey +1 -7
  3. data/lib/engineyard.rb +1 -22
  4. data/lib/engineyard/cli.rb +192 -94
  5. data/lib/engineyard/cli/#recipes.rb# +32 -0
  6. data/lib/engineyard/cli/api.rb +42 -28
  7. data/lib/engineyard/cli/recipes.rb +13 -6
  8. data/lib/engineyard/cli/ui.rb +103 -42
  9. data/lib/engineyard/cli/web.rb +16 -10
  10. data/lib/engineyard/config.rb +92 -18
  11. data/lib/engineyard/deploy_config.rb +66 -0
  12. data/lib/engineyard/deploy_config/migrate.rb +125 -0
  13. data/lib/engineyard/deploy_config/ref.rb +56 -0
  14. data/lib/engineyard/error.rb +38 -78
  15. data/lib/engineyard/repo.rb +75 -27
  16. data/lib/engineyard/serverside_runner.rb +133 -0
  17. data/lib/engineyard/thor.rb +110 -18
  18. data/lib/engineyard/version.rb +1 -1
  19. data/spec/engineyard/cli/api_spec.rb +10 -16
  20. data/spec/engineyard/cli_spec.rb +0 -11
  21. data/spec/engineyard/config_spec.rb +1 -8
  22. data/spec/engineyard/deploy_config_spec.rb +203 -0
  23. data/spec/engineyard/eyrc_spec.rb +2 -0
  24. data/spec/engineyard/repo_spec.rb +57 -34
  25. data/spec/ey/deploy_spec.rb +102 -52
  26. data/spec/ey/list_environments_spec.rb +69 -14
  27. data/spec/ey/login_spec.rb +11 -7
  28. data/spec/ey/logout_spec.rb +4 -4
  29. data/spec/ey/logs_spec.rb +6 -6
  30. data/spec/ey/recipes/apply_spec.rb +1 -1
  31. data/spec/ey/recipes/download_spec.rb +1 -1
  32. data/spec/ey/recipes/upload_spec.rb +6 -6
  33. data/spec/ey/rollback_spec.rb +3 -3
  34. data/spec/ey/ssh_spec.rb +9 -9
  35. data/spec/ey/status_spec.rb +2 -2
  36. data/spec/ey/whoami_spec.rb +9 -8
  37. data/spec/spec_helper.rb +18 -15
  38. data/spec/support/{fake_awsm.rb → git_repos.rb} +0 -14
  39. data/spec/support/helpers.rb +84 -28
  40. data/spec/support/matchers.rb +0 -16
  41. data/spec/support/shared_behavior.rb +83 -103
  42. metadata +65 -51
  43. data/lib/engineyard/api.rb +0 -117
  44. data/lib/engineyard/collection.rb +0 -7
  45. data/lib/engineyard/collection/abstract.rb +0 -71
  46. data/lib/engineyard/collection/apps.rb +0 -8
  47. data/lib/engineyard/collection/environments.rb +0 -8
  48. data/lib/engineyard/model.rb +0 -12
  49. data/lib/engineyard/model/account.rb +0 -8
  50. data/lib/engineyard/model/api_struct.rb +0 -33
  51. data/lib/engineyard/model/app.rb +0 -32
  52. data/lib/engineyard/model/deployment.rb +0 -90
  53. data/lib/engineyard/model/environment.rb +0 -194
  54. data/lib/engineyard/model/instance.rb +0 -166
  55. data/lib/engineyard/model/log.rb +0 -9
  56. data/lib/engineyard/model/user.rb +0 -6
  57. data/lib/engineyard/resolver.rb +0 -134
  58. data/lib/engineyard/rest_client_ext.rb +0 -9
  59. data/lib/engineyard/ruby_ext.rb +0 -9
  60. data/spec/engineyard/api_spec.rb +0 -39
  61. data/spec/engineyard/collection/apps_spec.rb +0 -16
  62. data/spec/engineyard/collection/environments_spec.rb +0 -16
  63. data/spec/engineyard/model/api_struct_spec.rb +0 -41
  64. data/spec/engineyard/model/environment_spec.rb +0 -198
  65. data/spec/engineyard/model/instance_spec.rb +0 -27
  66. data/spec/engineyard/resolver_spec.rb +0 -112
  67. data/spec/support/fake_awsm.ru +0 -245
  68. data/spec/support/scenarios.rb +0 -417
@@ -1,10 +1,5 @@
1
1
  module EY
2
2
  class << self
3
- def fake_awsm
4
- @fake_awsm ||= load_fake_awsm
5
- end
6
- alias_method :start_fake_awsm, :fake_awsm
7
-
8
3
  def define_git_repo(name, &setup)
9
4
  git_repo_setup[name] ||= setup
10
5
  end
@@ -31,15 +26,6 @@ module EY
31
26
 
32
27
  protected
33
28
 
34
- def load_fake_awsm
35
- config_ru = File.join(EY_ROOT, "spec/support/fake_awsm.ru")
36
- unless system("ruby -c '#{config_ru}' > /dev/null")
37
- raise SyntaxError, "There is a syntax error in fake_awsm.ru! fix it!"
38
- end
39
- @server = RealWeb.start_server_in_fork(config_ru)
40
- "http://localhost:#{@server.port}"
41
- end
42
-
43
29
  def git_repo_setup
44
30
  @git_repo_setup ||= {}
45
31
  end
@@ -24,19 +24,25 @@ module SpecHelpers
24
24
 
25
25
  module IntegrationHelpers
26
26
  def run_ey(command_options, ey_options={})
27
+
27
28
  if respond_to?(:extra_ey_options) # needed for ssh tests
28
29
  ey_options.merge!(extra_ey_options)
30
+ return ey(command_to_run(command_options), ey_options)
29
31
  end
30
32
 
31
- ey(command_to_run(command_options), ey_options)
33
+ if ey_options[:expect_failure]
34
+ fast_failing_ey(command_to_run(command_options))
35
+ else
36
+ fast_ey(command_to_run(command_options))
37
+ end
32
38
  end
33
39
 
34
- def make_scenario(hash)
40
+ def make_scenario(opts)
35
41
  # since nil will silently turn to empty string when interpolated,
36
42
  # and there's a lot of string matching involved in integration
37
43
  # testing, it would be nice to have early notification of typos.
38
44
  scenario = Hash.new { |h,k| raise "Tried to get key #{k.inspect}, but it's missing!" }
39
- scenario.merge!(hash)
45
+ scenario.merge!(opts)
40
46
  end
41
47
  end
42
48
 
@@ -69,21 +75,37 @@ module SpecHelpers
69
75
  ZeroExitStatus = Class.new(UnexpectedExit)
70
76
 
71
77
  def ey_api
72
- @api ||= EY::API.new('asdf')
78
+ @api ||= EY::CloudClient.new('asdf', EY::CLI::UI.new)
79
+ end
80
+
81
+ def ensure_eyrc
82
+ begin
83
+ unless (data = read_eyrc) and data['api_token']
84
+ raise ".eyrc has no token, specs will stall waiting for stdin authentication input"
85
+ end
86
+ rescue Errno::ENOENT => e
87
+ raise ".eyrc must be written before calling run_ey or specs will stall waiting for stdin authentication input"
88
+ end
73
89
  end
74
90
 
75
- def fast_ey(args)
76
- err, out = StringIO.new, StringIO.new
77
- capture_stderr_into(err) do
78
- capture_stdout_into(out) do
79
- with_env('DEBUG' => 'true') do
80
- EY::CLI.start(args)
91
+ def fast_ey(args, options = {})
92
+
93
+ ensure_eyrc
94
+
95
+ begin
96
+ err, out = StringIO.new, StringIO.new
97
+ debug = options[:debug] == false ? nil : 'true'
98
+ capture_stderr_into(err) do
99
+ capture_stdout_into(out) do
100
+ with_env('DEBUG' => debug) do
101
+ EY::CLI.start(args)
102
+ end
81
103
  end
82
104
  end
105
+ ensure
106
+ @err, @out = err.string, out.string
107
+ @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
83
108
  end
84
- ensure
85
- @err, @out = err.string, out.string
86
- @raw_ssh_commands, @ssh_commands = extract_ssh_commands(@out)
87
109
  end
88
110
 
89
111
  def fast_failing_ey(*args)
@@ -94,17 +116,8 @@ module SpecHelpers
94
116
  # SystemExit typically indicates a bogus command, which we
95
117
  # here in expected-to-fail land are entirely happy with.
96
118
  nil
97
- rescue EY::Error => e
98
- more_err, more_out = StringIO.new, StringIO.new
99
-
100
- capture_stderr_into(more_err) do
101
- capture_stdout_into(more_out) do
102
- EY.ui.print_exception(e)
103
- end
104
- end
105
-
106
- @err << more_err.string
107
- @out << more_out.string
119
+ rescue EY::Error, EY::CloudClient::Error => e
120
+ nil
108
121
  end
109
122
  end
110
123
 
@@ -123,7 +136,12 @@ module SpecHelpers
123
136
  end
124
137
 
125
138
  def ey(args = [], options = {}, &block)
139
+ if respond_to?(:extra_ey_options) # needed for ssh tests
140
+ options.merge!(extra_ey_options)
141
+ end
142
+
126
143
  hide_err = options.has_key?(:hide_err) ? options[:hide_err] : options[:expect_failure]
144
+
127
145
  path_prepends = options[:prepend_to_path]
128
146
 
129
147
  ey_env = {
@@ -154,6 +172,7 @@ module SpecHelpers
154
172
  with_env(ey_env) do
155
173
  exit_status = Open4::open4("#{eybin} #{Escape.shell_command(args)}") do |pid, stdin, stdout, stderr|
156
174
  block.call(stdin) if block
175
+ stdin.close
157
176
  @out = stdout.read
158
177
  @err = stderr.read
159
178
  end
@@ -172,7 +191,7 @@ module SpecHelpers
172
191
  end
173
192
 
174
193
  def extract_ssh_commands(output)
175
- raw_ssh_commands = @out.split(/\n/).find_all do |line|
194
+ raw_ssh_commands = [@out,@err].join("\n").split(/\n/).find_all do |line|
176
195
  line =~ /^bash -lc/ || line =~ /^ssh/
177
196
  end
178
197
 
@@ -198,9 +217,46 @@ module SpecHelpers
198
217
  [raw_ssh_commands, ssh_commands]
199
218
  end
200
219
 
201
- def api_scenario(scenario, remote = "user@git.host:path/to/repo.git")
202
- response = ::RestClient.put(EY.fake_awsm + '/scenario', {"scenario" => scenario, "remote" => remote}, {})
203
- raise "Setting scenario failed: #{response.inspect}" unless response.code == 200
220
+ DEPRECATED_SCENARIOS = {
221
+ "empty" => "User Name",
222
+ "one app without environment" => "App Without Env",
223
+ "one app, one environment, not linked" => "Unlinked App",
224
+ "two apps" => "Two Apps",
225
+ "one app, one environment" => "Linked App",
226
+ "two accounts, two apps, two environments, ambiguous" => "Multiple Ambiguous Accounts",
227
+ "one app, one environment, no instances" => "Linked App Not Running",
228
+ "one app, one environment, app master red" => "Linked App Red Master",
229
+ "one app, many environments" => "One App Many Envs",
230
+ "one app, many similarly-named environments" => "One App Similarly Named Envs",
231
+ "two apps, same git uri" => "Two Apps Same Git URI",
232
+ }
233
+
234
+ def api_scenario(old_name)
235
+ clean_eyrc # switching scenarios, always clean up
236
+ name = DEPRECATED_SCENARIOS[old_name]
237
+ @scenario = EY::CloudClient::Test::Scenario[name]
238
+ @scenario_email = @scenario.email
239
+ @scenario_password = @scenario.password
240
+ @scenario_api_token = @scenario.api_token
241
+ @scenario
242
+ end
243
+
244
+ def login_scenario(scenario_name)
245
+ scen = api_scenario(scenario_name)
246
+ write_eyrc('api_token' => scenario_api_token)
247
+ scen
248
+ end
249
+
250
+ def scenario_email
251
+ @scenario_email
252
+ end
253
+
254
+ def scenario_password
255
+ @scenario_password
256
+ end
257
+
258
+ def scenario_api_token
259
+ @scenario_api_token
204
260
  end
205
261
 
206
262
  def read_yaml(file)
@@ -26,19 +26,3 @@ RSpec::Matchers.define :have_app_code do
26
26
  "Expected #has_app_code? to be false on instance: #{instance.inspect}"
27
27
  end
28
28
  end
29
-
30
- RSpec::Matchers.define :resolve_to do |expected|
31
- match do |pair|
32
- app, env = *pair
33
- app.name == expected[:app_name] && env.name == expected[:environment_name]
34
- end
35
-
36
- failure_message_for_should do |pair|
37
- app, env = *pair
38
- "Expected: #{expected[:app_name]}, #{expected[:environment_name]}; Got: #{app.name}, #{env.name}"
39
- end
40
-
41
- failure_message_for_should_not do |pair|
42
- "Expected to not match: #{expected[:app_name]}, #{expected[:environment_name]}"
43
- end
44
- end
@@ -9,7 +9,7 @@ shared_examples_for "it has an ambiguous git repo" do
9
9
  use_git_repo('dup test')
10
10
 
11
11
  before(:all) do
12
- api_scenario "two apps, same git uri"
12
+ login_scenario "two apps, same git uri"
13
13
  end
14
14
  end
15
15
 
@@ -18,10 +18,9 @@ shared_examples_for "it requires an unambiguous git repo" do
18
18
 
19
19
  it "lists disambiguating environments to choose from" do
20
20
  run_ey({}, {:expect_failure => true})
21
- @err.should =~ /ambiguous/
22
- @err.should =~ /specify one of the following environments/
23
- @err.should =~ /giblets \(main\)/
24
- @err.should =~ /keycollector_production \(main\)/
21
+ @err.should include('Multiple environments possible, please be more specific')
22
+ @err.should =~ /giblets/
23
+ @err.should =~ /keycollector_production/
25
24
  end
26
25
  end
27
26
 
@@ -29,16 +28,28 @@ shared_examples_for "it takes an environment name and an app name and an account
29
28
  include_examples "it takes an app name"
30
29
  include_examples "it takes an environment name"
31
30
 
31
+ it "complains when you send --account without a value" do
32
+ login_scenario "empty"
33
+ fast_failing_ey command_to_run({}) << '--account'
34
+ @err.should include("No value provided for option '--account'")
35
+ fast_failing_ey command_to_run({}) << '-c'
36
+ @err.should include("No value provided for option '--account'")
37
+ end
38
+
32
39
  context "when multiple accounts with collaboration" do
33
40
  before :all do
34
- api_scenario "two accounts, two apps, two environments, ambiguous"
41
+ login_scenario "two accounts, two apps, two environments, ambiguous"
35
42
  end
36
43
 
37
44
  it "fails when the app and environment are ambiguous across accounts" do
38
- run_ey({:environment => "giblets", :app => "rails232app", :ref => 'master'}, {:expect_failure => true})
39
- @err.should match(/Multiple app deployments possible/i)
40
- @err.should match(/ey \S+ --environment='giblets' --app='rails232app' --account='account_2'/i)
41
- @err.should match(/ey \S+ --environment='giblets' --app='rails232app' --account='main'/i)
45
+ run_ey({:environment => "giblets", :app => "rails232app", :ref => 'master'}, {:expect_failure => !@succeeds_on_multiple_matches})
46
+ if @succeeds_on_multiple_matches
47
+ @err.should_not match(/multiple/i)
48
+ else
49
+ @err.should match(/Multiple application environments possible/i)
50
+ @err.should match(/ey \S+ --account='account_2' --app='rails232app' --environment='giblets'/i)
51
+ @err.should match(/ey \S+ --account='main' --app='rails232app' --environment='giblets'/i)
52
+ end
42
53
  end
43
54
 
44
55
  it "runs when specifying the account disambiguates the app to deploy" do
@@ -56,9 +67,17 @@ end
56
67
  shared_examples_for "it takes an environment name and an account name" do
57
68
  include_examples "it takes an environment name"
58
69
 
70
+ it "complains when you send --account without a value" do
71
+ login_scenario "empty"
72
+ fast_failing_ey command_to_run({}) << '--account'
73
+ @err.should include("No value provided for option '--account'")
74
+ fast_failing_ey command_to_run({}) << '-c'
75
+ @err.should include("No value provided for option '--account'")
76
+ end
77
+
59
78
  context "when multiple accounts with collaboration" do
60
79
  before :all do
61
- api_scenario "two accounts, two apps, two environments, ambiguous"
80
+ login_scenario "two accounts, two apps, two environments, ambiguous"
62
81
  end
63
82
 
64
83
  it "fails when the app and environment are ambiguous across accounts" do
@@ -86,9 +105,8 @@ shared_examples_for "it takes an environment name and an account name" do
86
105
  end
87
106
 
88
107
  it "returns the error message to the user" do
89
- lambda do
90
- fast_ey(command_to_run({:environment => "giblets", :account => "main"}))
91
- end.should raise_error(EY::Error, /400.*Important infos/)
108
+ fast_failing_ey(command_to_run({:environment => "giblets", :account => "main"}))
109
+ @err.should match(/400.*Important infos/)
92
110
  end
93
111
  end
94
112
 
@@ -97,8 +115,8 @@ end
97
115
 
98
116
  shared_examples_for "it takes an environment name" do
99
117
  it "operates on the current environment by default" do
100
- api_scenario "one app, one environment"
101
- run_ey({:environment => nil}, {:debug => true})
118
+ login_scenario "one app, one environment"
119
+ run_ey(:environment => nil)
102
120
  verify_ran(make_scenario({
103
121
  :environment => 'giblets',
104
122
  :application => 'rails232app',
@@ -108,9 +126,18 @@ shared_examples_for "it takes an environment name" do
108
126
  end
109
127
 
110
128
  it "complains when you specify a nonexistent environment" do
111
- api_scenario "one app, one environment"
112
- run_ey({:environment => 'typo-happens-here'}, {:expect_failure => true})
113
- @err.should match(/no environment named 'typo-happens-here'/i)
129
+ login_scenario "one app, one environment"
130
+ # This test must shell out (not sure why, plz FIXME)
131
+ ey command_to_run(:environment => 'typo-happens-here'), {:expect_failure => true}
132
+ @err.should match(/No environment found matching .*typo-happens-here/i)
133
+ end
134
+
135
+ it "complains when you send --environment without a value" do
136
+ login_scenario "empty"
137
+ fast_failing_ey command_to_run({}) << '--environment'
138
+ @err.should include("No value provided for option '--environment'")
139
+ fast_failing_ey command_to_run({}) << '-e'
140
+ @err.should include("No value provided for option '--environment'")
114
141
  end
115
142
 
116
143
  context "outside a git repo" do
@@ -126,7 +153,7 @@ shared_examples_for "it takes an environment name" do
126
153
  use_git_repo("not actually a git repo")
127
154
 
128
155
  before :all do
129
- api_scenario "one app, one environment"
156
+ login_scenario "one app, one environment"
130
157
  end
131
158
 
132
159
  it "works (and does not complain about git remotes)" do
@@ -137,44 +164,57 @@ shared_examples_for "it takes an environment name" do
137
164
 
138
165
  context "given a piece of the environment name" do
139
166
  before(:all) do
140
- api_scenario "one app, many similarly-named environments"
167
+ login_scenario "one app, many similarly-named environments"
141
168
  end
142
169
 
143
170
  it "complains when the substring is ambiguous" do
144
- run_ey({:environment => 'staging'}, {:expect_failure => true})
145
- if @takes_app_name
146
- @err.should match(/multiple app deployments possible/i)
171
+ run_ey({:environment => 'staging'}, {:expect_failure => !@succeeds_on_multiple_matches})
172
+
173
+ if @succeeds_on_multiple_matches
174
+ @err.should_not match(/multiple .* possible/i)
147
175
  else
148
- @err.should match(/multiple environments possible/i)
176
+ if @takes_app_name
177
+ @err.should match(/multiple application environments possible/i)
178
+ else
179
+ @err.should match(/multiple environments possible/i)
180
+ end
149
181
  end
150
182
  end
151
183
 
152
184
  it "works when the substring is unambiguous" do
153
- api_scenario "one app, many similarly-named environments"
154
- run_ey({:environment => 'prod'}, {:debug => true})
185
+ login_scenario "one app, many similarly-named environments"
186
+ run_ey({:environment => 'prod', :migrate => true}, {:debug => true})
155
187
  verify_ran(make_scenario({
156
- :environment => 'railsapp_production',
157
- :application => 'rails232app',
158
- :master_hostname => 'app_master_hostname.compute-1.amazonaws.com',
159
- :ssh_username => 'turkey',
160
- }))
188
+ :environment => 'railsapp_production',
189
+ :application => 'rails232app',
190
+ :master_hostname => 'app_master_hostname.compute-1.amazonaws.com',
191
+ :ssh_username => 'turkey',
192
+ }))
161
193
  end
162
194
  end
163
195
 
164
196
  it "complains when it can't guess the environment and its name isn't specified" do
165
- api_scenario "one app, one environment, not linked"
197
+ login_scenario "one app without environment"
166
198
  run_ey({:environment => nil}, {:expect_failure => true})
167
- @err.should match(/there is no application configured/i)
199
+ @err.should match(/No environment found for applications matching remotes:/i)
168
200
  end
169
201
  end
170
202
 
171
203
  shared_examples_for "it takes an app name" do
172
204
  before { @takes_app_name = true }
173
205
 
206
+ it "complains when you send --app without a value" do
207
+ login_scenario "empty"
208
+ fast_failing_ey command_to_run({}) << '--app'
209
+ @err.should include("No value provided for option '--app'")
210
+ fast_failing_ey command_to_run({}) << '-a'
211
+ @err.should include("No value provided for option '--app'")
212
+ end
213
+
174
214
  it "allows you to specify a valid app" do
175
- api_scenario "one app, one environment"
215
+ login_scenario "one app, one environment"
176
216
  Dir.chdir(Dir.tmpdir) do
177
- run_ey({:environment => 'giblets', :app => 'rails232app', :ref => 'master'}, {})
217
+ run_ey({:environment => 'giblets', :app => 'rails232app', :ref => 'master', :migrate => nil}, {})
178
218
  verify_ran(make_scenario({
179
219
  :environment => 'giblets',
180
220
  :application => 'rails232app',
@@ -185,9 +225,9 @@ shared_examples_for "it takes an app name" do
185
225
  end
186
226
 
187
227
  it "can guess the environment from the app" do
188
- api_scenario "two apps"
228
+ login_scenario "two apps"
189
229
  Dir.chdir(Dir.tmpdir) do
190
- run_ey({:app => 'rails232app', :ref => 'master'}, {})
230
+ run_ey({:app => 'rails232app', :ref => 'master', :migrate => true}, {})
191
231
  verify_ran(make_scenario({
192
232
  :environment => 'giblets',
193
233
  :application => 'rails232app',
@@ -198,10 +238,10 @@ shared_examples_for "it takes an app name" do
198
238
  end
199
239
 
200
240
  it "complains when you specify a nonexistant app" do
201
- api_scenario "one app, one environment"
241
+ login_scenario "one app, one environment"
202
242
  run_ey({:environment => 'giblets', :app => 'P-time-SAT-solver', :ref => 'master'},
203
243
  {:expect_failure => true})
204
- @err.should =~ /no app.*P-time-SAT-solver/i
244
+ @err.should =~ /No app.*P-time-SAT-solver/i
205
245
  end
206
246
 
207
247
  end
@@ -209,7 +249,7 @@ end
209
249
  shared_examples_for "it invokes engineyard-serverside" do
210
250
  context "with arguments" do
211
251
  before(:all) do
212
- api_scenario "one app, one environment"
252
+ login_scenario "one app, one environment"
213
253
  run_ey({:environment => 'giblets', :verbose => true})
214
254
  end
215
255
 
@@ -239,8 +279,8 @@ shared_examples_for "it invokes engineyard-serverside" do
239
279
 
240
280
  context "when no instances have names" do
241
281
  before(:each) do
242
- api_scenario "two apps"
243
- run_ey({:env => 'giblets', :app => 'rails232app', :ref => 'master', :verbose => true})
282
+ login_scenario "two apps"
283
+ run_ey({:env => 'giblets', :app => 'rails232app', :ref => 'master', :migrate => true, :verbose => true})
244
284
  end
245
285
 
246
286
  it "omits the --instance-names parameter" do
@@ -248,63 +288,3 @@ shared_examples_for "it invokes engineyard-serverside" do
248
288
  end
249
289
  end
250
290
  end
251
-
252
- shared_examples_for "model collections" do
253
- describe "#match_one" do
254
- it "works when given an unambiguous substring" do
255
- @collection.match_one("prod").name.should == "app_production"
256
- end
257
-
258
- it "raises an error when given an ambiguous substring" do
259
- lambda {
260
- @collection.match_one("staging")
261
- }.should raise_error(@collection_class.ambiguous_error)
262
- end
263
-
264
- it "returns an exact match if one exists" do
265
- @collection.match_one("app_staging").name.should == "app_staging"
266
- end
267
-
268
- it "returns nil when it can't find anything" do
269
- @collection.match_one("dev-and-production").should be_nil
270
- end
271
- end
272
-
273
- describe "#match_one!" do
274
- it "works when given an unambiguous substring" do
275
- @collection.match_one!("prod").name.should == "app_production"
276
- end
277
-
278
- it "raises an error when given an ambiguous substring" do
279
- lambda {
280
- @collection.match_one!("staging")
281
- }.should raise_error(@collection_class.ambiguous_error)
282
- end
283
-
284
- it "returns an exact match if one exists" do
285
- @collection.match_one!("app_staging").name.should == "app_staging"
286
- end
287
-
288
- it "raises an error when given an ambiguous exact string" do
289
- lambda {
290
- @collection.match_one!("app_duplicate")
291
- }.should raise_error(@collection_class.ambiguous_error)
292
- end
293
-
294
- it "raises an error when it can't find anything" do
295
- lambda {
296
- @collection.match_one!("dev-and-production")
297
- }.should raise_error(@collection_class.invalid_error)
298
- end
299
- end
300
-
301
- describe "#named" do
302
- it "finds matching by name" do
303
- @collection.named("app_staging").name.should == "app_staging"
304
- end
305
-
306
- it "returns nil when no name matches" do
307
- @collection.named("something else").should be_nil
308
- end
309
- end
310
- end