cf 5.0.0.rc1 → 5.0.0.rc3

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 (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