cf 5.0.0.rc1 → 5.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/lib/admin/plugin.rb +1 -0
  2. data/lib/admin/service_broker/add.rb +46 -0
  3. data/lib/cf/cli.rb +8 -3
  4. data/lib/cf/cli/service/create.rb +68 -20
  5. data/lib/cf/cli/service/delete.rb +1 -1
  6. data/lib/cf/cli/service/service_instance_helper.rb +99 -0
  7. data/lib/cf/cli/service/services.rb +12 -32
  8. data/lib/cf/cli/start/target.rb +1 -1
  9. data/lib/cf/version.rb +1 -1
  10. data/lib/manifests/manifests.rb +41 -25
  11. data/lib/tasks/gem_release.rake +1 -1
  12. data/spec/admin/service_broker/add_spec.rb +59 -0
  13. data/spec/assets/env/Gemfile +4 -0
  14. data/spec/assets/env/Gemfile.lock +20 -0
  15. data/spec/assets/env/env_test.rb +58 -0
  16. data/spec/cf/cli/app/delete_spec.rb +2 -2
  17. data/spec/cf/cli/app/push/create_spec.rb +1 -1
  18. data/spec/cf/cli/service/create_spec.rb +51 -4
  19. data/spec/cf/cli/service/rename_spec.rb +1 -1
  20. data/spec/cf/cli/service/service_instance_helper_spec.rb +155 -0
  21. data/spec/cf/cli/service/services_spec.rb +63 -34
  22. data/spec/cf/cli/space/space_spec.rb +1 -1
  23. data/spec/cf/cli/space/spaces_spec.rb +3 -3
  24. data/spec/factories/cfoundry/v2/{service_instances_factory.rb → managed_service_instances_factory.rb} +2 -2
  25. data/spec/factories/cfoundry/v2/user_provided_service_instances_factory.rb +12 -0
  26. data/spec/features/delete_orphaned_service_spec.rb +64 -0
  27. data/spec/features/manifests_spec.rb +86 -0
  28. data/spec/features/org_spec.rb +4 -4
  29. data/spec/{integration → features}/push_flow_spec.rb +27 -3
  30. data/spec/features/services_spec.rb +96 -0
  31. data/spec/integration/service_broker_spec.rb +49 -0
  32. data/spec/manifests/manifests_spec.rb +46 -25
  33. data/spec/spec_helper.rb +7 -1
  34. data/spec/support/features_helper.rb +36 -3
  35. data/spec/support/matchers.rb +14 -3
  36. metadata +109 -9
@@ -10,7 +10,7 @@ namespace :gem do
10
10
  sh! "git add lib/cf/version.rb"
11
11
 
12
12
  print_with_purpose "Bumping to version #{gem_version}"
13
- #generate_release_notes(old_version)
13
+ generate_release_notes(old_version)
14
14
  sh!("git commit -m 'Bumping to version #{gem_version}.'")
15
15
  sh!("git push")
16
16
  sh!("gem release --tag")
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ describe CFAdmin::ServiceBroker::Add do
4
+ let(:fake_home_dir) { "#{SPEC_ROOT}/fixtures/fake_admin_dir" }
5
+
6
+ stub_home_dir_with { fake_home_dir }
7
+
8
+ let(:client) { build(:client) }
9
+
10
+ let(:service_broker) { CFoundry::V2::ServiceBroker.new(nil, client) }
11
+
12
+ before do
13
+ CFAdmin::ServiceBroker::Add.client = client
14
+ client.stub(:service_broker).and_return(service_broker)
15
+ end
16
+
17
+ it "creates a service broker when arguments are provided on the command line" do
18
+ service_broker.stub(:create!)
19
+
20
+ cf %W[add-service-broker --name cf-mysql --url http://cf-mysql.cfapp.io --token cfmysqlsecret]
21
+
22
+ service_broker.name.should == 'cf-mysql'
23
+ service_broker.broker_url.should == 'http://cf-mysql.cfapp.io'
24
+ service_broker.token.should == 'cfmysqlsecret'
25
+
26
+ service_broker.should have_received(:create!)
27
+ end
28
+
29
+ it "creates a service broker when only the name is provided" do
30
+ service_broker.stub(:create!)
31
+
32
+ stub_ask("url").and_return("http://example.com")
33
+ stub_ask("token").and_return("token")
34
+
35
+ cf %W[add-service-broker cf-mysql]
36
+
37
+ service_broker.name.should == 'cf-mysql'
38
+ service_broker.broker_url.should == 'http://example.com'
39
+ service_broker.token.should == 'token'
40
+
41
+ service_broker.should have_received(:create!)
42
+ end
43
+
44
+ it "creates a service broker when no arguments are provided" do
45
+ service_broker.stub(:create!)
46
+
47
+ stub_ask("name").and_return("cf-mysql")
48
+ stub_ask("url").and_return("http://example.com")
49
+ stub_ask("token").and_return("token")
50
+
51
+ cf %W[add-service-broker]
52
+
53
+ service_broker.name.should == 'cf-mysql'
54
+ service_broker.broker_url.should == 'http://example.com'
55
+ service_broker.token.should == 'token'
56
+
57
+ service_broker.should have_received(:create!)
58
+ end
59
+ end
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+ gem 'bundler'
3
+ gem 'sinatra'
4
+ gem 'json'
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ json (1.8.0)
5
+ rack (1.5.2)
6
+ rack-protection (1.5.0)
7
+ rack
8
+ sinatra (1.4.3)
9
+ rack (~> 1.4)
10
+ rack-protection (~> 1.4)
11
+ tilt (~> 1.3, >= 1.3.4)
12
+ tilt (1.4.1)
13
+
14
+ PLATFORMS
15
+ ruby
16
+
17
+ DEPENDENCIES
18
+ bundler
19
+ json
20
+ sinatra
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'sinatra'
4
+ require 'json'
5
+
6
+ $stdout.sync = true
7
+
8
+ def dump_env(fmt)
9
+ if fmt == 'html' || fmt == nil
10
+ res = ''
11
+ ENV.each do |k, v|
12
+ res << "#{k}: #{v}<br/>"
13
+ end
14
+ res
15
+ elsif fmt == 'json'
16
+ res = {}
17
+ ENV.each do |k, v|
18
+ res[k] = v
19
+ end
20
+ puts res
21
+ res.to_json
22
+ end
23
+ end
24
+
25
+ get '/' do
26
+ dump_env('html')
27
+ end
28
+
29
+ get '/healthcheck' do
30
+ "OK"
31
+ end
32
+
33
+ get '/env' do
34
+ dump_env('json')
35
+ end
36
+
37
+
38
+ get '/services' do
39
+ app_instance = JSON.parse(ENV['VCAP_APPLICATION'])
40
+ services = JSON.parse(ENV['VCAP_SERVICES'])
41
+
42
+ valid_services = false
43
+ service_list = []
44
+ services.each do |k, v|
45
+ v.each do |i|
46
+ s = {}
47
+ s['vendor'] = k.split('-')[0]
48
+ s['name'] = i['name']
49
+ service_list << s
50
+ valid_services = true
51
+ end
52
+ end
53
+ response = "{\"status\":\"ok\", \"services\": #{service_list.to_json}}" if valid_services
54
+ response = "{\"status\":\"fail\", \"services\": []}" if !valid_services
55
+
56
+ puts "my response: #{response}"
57
+ response
58
+ end
@@ -52,8 +52,8 @@ module CF
52
52
  end
53
53
 
54
54
  context "when there are apps" do
55
- let(:service_1) { build(:service_instance, :name => "service-instance-name-1") }
56
- let(:service_2) { build(:service_instance, :name => "service-instance-name-2") }
55
+ let(:service_1) { build(:managed_service_instance, :name => "service-instance-name-1") }
56
+ let(:service_2) { build(:managed_service_instance, :name => "service-instance-name-2") }
57
57
 
58
58
  let(:service_binding_1) { build(:service_binding, :service_instance => service_1) }
59
59
  let(:service_binding_2) { build(:service_binding, :service_instance => service_2) }
@@ -7,7 +7,7 @@ module CF
7
7
  let(:given) { {} }
8
8
  let(:global) { {:color => false, :quiet => true} }
9
9
 
10
- let(:service_instances) { Array.new(5) { build(:service_instance) } }
10
+ let(:service_instances) { Array.new(5) { build(:managed_service_instance) } }
11
11
  let(:lucid64) { build(:stack, :name => "lucid64") }
12
12
  let(:client) { build(:client) }
13
13
 
@@ -73,8 +73,8 @@ module CF
73
73
  } }
74
74
 
75
75
  it "creates the specified service" do
76
- CFoundry::V2::ServiceInstance.any_instance.should_receive(:service_plan=).with(service_plan)
77
- CFoundry::V2::ServiceInstance.any_instance.should_receive(:create!)
76
+ CFoundry::V2::ManagedServiceInstance.any_instance.should_receive(:service_plan=).with(service_plan)
77
+ CFoundry::V2::ManagedServiceInstance.any_instance.should_receive(:create!)
78
78
  capture_output { command }
79
79
  end
80
80
  end
@@ -89,11 +89,58 @@ module CF
89
89
  let(:services) { [selected_service] }
90
90
 
91
91
  it "uses case insensitive match" do
92
- CFoundry::V2::ServiceInstance.any_instance.should_receive(:service_plan=).with(service_plan)
93
- CFoundry::V2::ServiceInstance.any_instance.should_receive(:create!)
92
+ CFoundry::V2::ManagedServiceInstance.any_instance.should_receive(:service_plan=).with(service_plan)
93
+ CFoundry::V2::ManagedServiceInstance.any_instance.should_receive(:create!)
94
94
  capture_output { command }
95
95
  end
96
96
  end
97
+
98
+ describe "when selecting the user-provided service" do
99
+ let(:services) { [build(:service), build(:service)] }
100
+ let(:user_provided_service) { build(:service, label: "user-provided")}
101
+
102
+ before do
103
+ client.stub(:services).and_return(services)
104
+ end
105
+
106
+ it "asks for an instance name and credentials" do
107
+ should_ask("What kind?", hash_including(choices: include(has_label("user-provided")))) { user_provided_service }
108
+ should_ask("Name?", anything) { "user-provided-service-name-1" }
109
+
110
+ should_ask("What credential parameters should applications use to connect to this service instance?\n(e.g. hostname, port, password)") { "host, port, user name" }
111
+ should_print("'user name' is not a valid key")
112
+ should_ask("What credential parameters should applications use to connect to this service instance?\n(e.g. hostname, port, password)") { "host, port" }
113
+ should_ask("host") { "example.com" }
114
+ should_ask("port") { "8080" }
115
+ mock_with_progress("Creating service user-provided-service-name-1")
116
+
117
+ instance = client.user_provided_service_instance
118
+ client.should_receive(:user_provided_service_instance).and_return(instance)
119
+ instance.should_receive(:create!)
120
+
121
+ capture_output { command }
122
+
123
+ instance.credentials['host'].should == 'example.com'
124
+ instance.credentials['port'].should == '8080'
125
+ end
126
+
127
+ # lame, i know
128
+ context "when invoked from another command" do
129
+ let(:params) { {
130
+ :credentials => {"k" => "v"},
131
+ :name => "service-name",
132
+ :offering => UPDummy.new,
133
+ } }
134
+
135
+ it "creates a user-provided service" do
136
+ instance = client.user_provided_service_instance
137
+ client.should_receive(:user_provided_service_instance).and_return(instance)
138
+ instance.should_receive(:create!)
139
+
140
+ Mothership.new.invoke(:create_service, params, {})
141
+ end
142
+ end
143
+ end
97
144
  end
98
145
  end
99
146
  end
@@ -51,7 +51,7 @@ describe CF::Service::Rename do
51
51
  end
52
52
 
53
53
  context "when there are services" do
54
- let(:services) { Array.new(2) { build(:service_instance) } }
54
+ let(:services) { Array.new(2) { build(:managed_service_instance) } }
55
55
  let(:renamed_service) { services.first }
56
56
 
57
57
  context "when the defaults are used" do
@@ -0,0 +1,155 @@
1
+ require "spec_helper"
2
+
3
+ describe ServiceInstanceHelper do
4
+ describe ".new" do
5
+ let(:provided_instance) { build(:user_provided_service_instance) }
6
+ let(:managed_instance) { build(:managed_service_instance) }
7
+
8
+ it "returns a ManagedSerivceInstanceHelper when the argument is a ManagedServiceInstance" do
9
+ expect(ServiceInstanceHelper.new(managed_instance)).to be_a ManagedServiceInstanceHelper
10
+ end
11
+
12
+ it "returns a ManagedSerivceInstanceHelper when the argument is a ManagedServiceInstance" do
13
+ expect(ServiceInstanceHelper.new(provided_instance)).to be_a UserProvidedServiceInstanceHelper
14
+ end
15
+ end
16
+ end
17
+
18
+ describe UserProvidedServiceInstanceHelper do
19
+ let(:bindings) { [] }
20
+ let(:instance) { build(:user_provided_service_instance, service_bindings: bindings) }
21
+ subject(:helper) { UserProvidedServiceInstanceHelper.new(instance) }
22
+ describe "matches" do
23
+ it "returns true when 'user-provided' is the given label" do
24
+ expect(helper.matches(service: "user-provided")).to eq true
25
+ end
26
+
27
+ it "returns false when 'user-provided' is not the given label" do
28
+ expect(helper.matches(service: "a-different-label")).to eq false
29
+ end
30
+
31
+ it "returns true when a label is not given" do
32
+ expect(helper.matches).to eq true
33
+ end
34
+ end
35
+
36
+ its(:service_label) { should eq("user-provided") }
37
+ its(:service_provider) { should eq("n/a") }
38
+ its(:version) { should eq("n/a") }
39
+ its(:plan_name) { should eq("n/a") }
40
+ its(:name) { should eq instance.name }
41
+ its(:service_bindings) { should eq instance.service_bindings }
42
+ end
43
+
44
+ describe ManagedServiceInstanceHelper do
45
+ let(:label) { "some-label" }
46
+ let(:provider) { "some-provider" }
47
+ let(:version) { "some-version" }
48
+ let(:plan_name) { "some-plan-name" }
49
+
50
+ let(:service) { build(:service, label: label, provider: provider, version: version) }
51
+ let(:plan) { build(:service_plan, service: service, name: plan_name) }
52
+ let(:bindings) { [] }
53
+ let(:instance) { build(:managed_service_instance, service_plan: plan, service_bindings: bindings) }
54
+ subject(:helper) { ManagedServiceInstanceHelper.new(instance) }
55
+
56
+ describe "matches" do
57
+ it "returns true when no condition is specified" do
58
+ expect(helper.matches).to eq(true)
59
+ end
60
+
61
+ context "filtering based on service" do
62
+ it "returns true if the service label matches given service" do
63
+ expect(helper.matches(service: label)).to eq(true)
64
+ end
65
+
66
+ it "returns false if the service label does not match given service" do
67
+ expect(helper.matches(service: "a-different-label")).to eq(false)
68
+ end
69
+ end
70
+
71
+ context "filtering based on service plan" do
72
+ it "returns true if the plan name matches given plan" do
73
+ expect(helper.matches(plan: plan_name)).to eq(true)
74
+ end
75
+
76
+ it "returns true if the plan name does not match given plan" do
77
+ expect(helper.matches(plan: "some-other-plan-name")).to eq(false)
78
+ end
79
+
80
+ it "is case insensitive" do
81
+ expect(helper.matches(plan: plan_name.upcase)).to eq(true)
82
+ end
83
+ end
84
+
85
+ context "filtering based on provider" do
86
+ it "returns true if the provider name matches given provider" do
87
+ expect(helper.matches(provider: provider)).to eq(true)
88
+ end
89
+
90
+ it "returns true if the provider does not match given provider" do
91
+ expect(helper.matches(provider: "a-different-provider")).to eq(false)
92
+ end
93
+ end
94
+
95
+ context "filtering based on version" do
96
+ it "returns true if the version matches given version" do
97
+ expect(helper.matches(version: version)).to eq(true)
98
+ end
99
+
100
+ it "returns true if the version does not match given version" do
101
+ expect(helper.matches(version: "a-different-version")).to eq(false)
102
+ end
103
+ end
104
+
105
+ context "multiple filters" do
106
+ it "returns true if the service instance matches all four parameters" do
107
+ expect(helper.matches(service: label, plan: plan_name,
108
+ provider: provider, version: version)).to eq true
109
+ end
110
+
111
+ it "return false if any of the parameters does not match the attribute of the service instance" do
112
+ expect(helper.matches(service: label, plan: plan_name,
113
+ provider: provider, version: "a-different-version")).to eq false
114
+ end
115
+ end
116
+
117
+ context "with patterns for args" do
118
+ it "returns true when service label matches the given glob" do
119
+ expect(helper.matches(service: label.gsub(/.$/, "*"))).to eq(true)
120
+ end
121
+
122
+ it "returns false when the service label doesn not match the given glob" do
123
+ expect(helper.matches(service: label + "_*")).to eq(false)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "service_label" do
129
+
130
+ it "returns the label of instance's service offering" do
131
+ expect(helper.service_label).to eq label
132
+ end
133
+ end
134
+
135
+ describe "service_provider" do
136
+ it "returns the provider of the instance's service offering" do
137
+ expect(helper.service_provider).to eq provider
138
+ end
139
+ end
140
+
141
+ describe "version" do
142
+ it "returns the version of the instance's service offering" do
143
+ expect(helper.version).to eq version
144
+ end
145
+ end
146
+
147
+ describe "plan_name" do
148
+ it "returns the name of the instance's service plan" do
149
+ expect(helper.plan_name).to eq plan_name
150
+ end
151
+ end
152
+
153
+ its(:name) { should eq instance.name }
154
+ its(:service_bindings) { should eq instance.service_bindings }
155
+ end
@@ -42,29 +42,34 @@ module CF
42
42
 
43
43
  let(:service_plan) { build(:service_plan, :service => build(:service, :version => "service_version", :provider => "provider")) }
44
44
  let(:service_binding) { build(:service_binding, :app => app) }
45
- let(:service1) { build(:service_instance, :service_plan => service_plan, :service_bindings => [service_binding]) }
45
+ let(:service1) { build(:managed_service_instance, :service_plan => service_plan, :service_bindings => [service_binding]) }
46
46
 
47
47
  let(:service_instances) { [service1] }
48
48
  let(:current_space) { build(:space, :name => "the space") }
49
49
 
50
50
  subject do
51
- capture_output { Mothership.new.invoke(:services, inputs, given, global) }
51
+ capture_output { CF::CLI.new.invoke(:services, inputs, given, global) }
52
52
  end
53
53
 
54
54
  before do
55
- stub_client_and_precondition
55
+ stub_client
56
56
  client.stub(:service_bindings).and_return([service_binding])
57
57
  end
58
58
 
59
- it "produces a table of services" do
60
- subject
61
- stdout.rewind
62
- output = stdout.read
59
+ context "when the user is targeted to a space" do
60
+ before do
61
+ stub_precondition
62
+ end
63
+
64
+ it "produces a table of services" do
65
+ subject
66
+ stdout.rewind
67
+ output = stdout.read
63
68
 
64
- expect(output).to match /Getting services in the space.*OK/
69
+ expect(output).to match /Getting services in the space.*OK/
65
70
 
66
- expect(output).to match /name\s+service\s+provider\s+version\s+plan\s+bound apps/
67
- expect(output).to match /service-instance-.+?\s+ # name
71
+ expect(output).to match /name\s+service\s+provider\s+version\s+plan\s+bound apps/
72
+ expect(output).to match /service-instance-.+?\s+ # name
68
73
  service-.*?\s+ # service
69
74
  provider.*?\s+ # provider
70
75
  service_version\s+ # version
@@ -72,45 +77,69 @@ module CF
72
77
  app-name-\d+\s+ # bound apps
73
78
  /x
74
79
 
75
- end
80
+ end
76
81
 
77
- context "when one of the services does not have a service plan" do
78
- let(:service_instances) { [service1, service2]}
79
- let(:service2) { build(:service_instance, :service_plan => nil, :service_bindings => [service_binding]) }
80
- it 'still produces a table of service' do
81
- subject
82
- stdout.rewind
83
- output = stdout.read
82
+ context "when one of the services does not have a service plan" do
83
+ let(:service_instances) { [service1, service2]}
84
+ let(:service2) { build(:user_provided_service_instance, :service_bindings => [service_binding]) }
84
85
 
85
- expect(output).to match /Getting services in the space.*OK/
86
+ it 'still produces a table of service' do
87
+ subject
88
+ stdout.rewind
89
+ output = stdout.read
86
90
 
87
- expect(output).to match /name\s+service\s+provider\s+version\s+plan\s+bound apps/
91
+ expect(output).to match /Getting services in the space.*OK/
88
92
 
89
- expect(output).to match /service-instance-.+?\s+ # name
93
+ expect(output).to match /name\s+service\s+provider\s+version\s+plan\s+bound apps/
94
+
95
+ expect(output).to match /service-instance-.+?\s+ # name
90
96
  service-.*?\s+ # service
91
97
  provider.*?\s+ # provider
92
98
  service_version\s+ # version
93
99
  service-plan-.*?\s+ # plan
94
- app-name-\d+\s+ # bound apps
100
+ app-name-\d+\s+ # bound apps
95
101
  /x
96
102
 
97
- expect(output).to match /service-instance-.+?\s+ # name
98
- none\s+ # service
99
- none\s+ # provider
100
- none\s+ # version
101
- none\s+ # plan
102
- app-name-\d+\s+ # bound apps
103
+ expect(output).to match /service-instance-.+?\s+ # name
104
+ user-provided\s+ # service
105
+ n\/a\s+ # provider
106
+ n\/a\s+ # version
107
+ n\/a\s+ # plan
108
+ app-name-\d+\s+ # bound apps
103
109
  /x
110
+ end
111
+ end
112
+
113
+ context 'when given --marketplace argument' do
114
+ it 'lists services on the target' do
115
+ client.stub(:services => Array.new(3) { build(:service) })
116
+ cf %W[services --marketplace]
117
+ expect(output).to say("Getting services... OK")
118
+ expect(output).to say(/service\s+version\s+provider\s+plans\s+description/)
119
+ end
104
120
  end
105
121
  end
106
122
 
123
+ context "when the user is not targeted to a space" do
124
+ before do
125
+ service_command.stub(:check_logged_in).and_return(true)
126
+ client.stub(:current_organization).and_return(true)
127
+ end
128
+ let(:service_command) { CF::Service::Services.new(nil, {}) }
129
+ let(:current_space) { nil }
130
+
131
+ subject do
132
+ capture_output { service_command.execute(:services, inputs, global) }
133
+
134
+ #capture_output { CF::CLI.new.invoke(:services, inputs, given, global) }
135
+ end
136
+
137
+ it "returns an error" do
138
+ subject
139
+ stdout.rewind
140
+ output = stderr.read
107
141
 
108
- context 'when given --marketplace argument' do
109
- it 'lists services on the target' do
110
- client.stub(:services => Array.new(3) { build(:service) })
111
- cf %W[services --marketplace]
112
- expect(output).to say("Getting services... OK")
113
- expect(output).to say(/service\s+version\s+provider\s+plans\s+description/)
142
+ expect(output.to_s).to match "Please select a space with 'cf target --space SPACE_NAME'"
114
143
  end
115
144
  end
116
145
  end