af 0.3.12

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 (45) hide show
  1. data/LICENSE +24 -0
  2. data/README.md +92 -0
  3. data/Rakefile +17 -0
  4. data/bin/af +6 -0
  5. data/lib/cli.rb +30 -0
  6. data/lib/cli/commands/admin.rb +77 -0
  7. data/lib/cli/commands/apps.rb +940 -0
  8. data/lib/cli/commands/base.rb +79 -0
  9. data/lib/cli/commands/misc.rb +128 -0
  10. data/lib/cli/commands/services.rb +86 -0
  11. data/lib/cli/commands/user.rb +60 -0
  12. data/lib/cli/config.rb +110 -0
  13. data/lib/cli/core_ext.rb +119 -0
  14. data/lib/cli/errors.rb +19 -0
  15. data/lib/cli/frameworks.rb +109 -0
  16. data/lib/cli/runner.rb +490 -0
  17. data/lib/cli/services_helper.rb +78 -0
  18. data/lib/cli/usage.rb +104 -0
  19. data/lib/cli/version.rb +7 -0
  20. data/lib/cli/zip_util.rb +77 -0
  21. data/lib/vmc.rb +3 -0
  22. data/lib/vmc/client.rb +451 -0
  23. data/lib/vmc/const.rb +21 -0
  24. data/spec/assets/app_info.txt +9 -0
  25. data/spec/assets/app_listings.txt +9 -0
  26. data/spec/assets/bad_create_app.txt +9 -0
  27. data/spec/assets/delete_app.txt +9 -0
  28. data/spec/assets/global_service_listings.txt +9 -0
  29. data/spec/assets/good_create_app.txt +9 -0
  30. data/spec/assets/good_create_service.txt +9 -0
  31. data/spec/assets/info_authenticated.txt +27 -0
  32. data/spec/assets/info_return.txt +15 -0
  33. data/spec/assets/info_return_bad.txt +16 -0
  34. data/spec/assets/list_users.txt +13 -0
  35. data/spec/assets/login_fail.txt +9 -0
  36. data/spec/assets/login_success.txt +9 -0
  37. data/spec/assets/sample_token.txt +1 -0
  38. data/spec/assets/service_already_exists.txt +9 -0
  39. data/spec/assets/service_listings.txt +9 -0
  40. data/spec/assets/service_not_found.txt +9 -0
  41. data/spec/assets/user_info.txt +9 -0
  42. data/spec/spec_helper.rb +11 -0
  43. data/spec/unit/cli_opts_spec.rb +68 -0
  44. data/spec/unit/client_spec.rb +332 -0
  45. metadata +221 -0
@@ -0,0 +1,21 @@
1
+ module VMC
2
+
3
+ # This is the internal VMC version number, and is not necessarily
4
+ # the same as the RubyGem version (VMC::Cli::VERSION).
5
+ VERSION = '0.3.2'
6
+
7
+ # Targets
8
+ DEFAULT_TARGET = 'https://api.cloudfoundry.com'
9
+ DEFAULT_LOCAL_TARGET = 'http://api.vcap.me'
10
+
11
+ # General Paths
12
+ INFO_PATH = '/info'
13
+ GLOBAL_SERVICES_PATH = '/info/services'
14
+ RESOURCES_PATH = '/resources'
15
+
16
+ # User specific paths
17
+ APPS_PATH = '/apps'
18
+ SERVICES_PATH = '/services'
19
+ USERS_PATH = '/users'
20
+
21
+ end
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Fri, 04 Mar 2011 02:56:21 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 243
8
+
9
+ {"resources":{"memory":64},"uris":["foo.vcap.me"],"staging":{"stack":"ruby foo.rb","model":"http://b20nine.com/unknown"},"state":"STARTED","instances":1,"name":"foo","meta":{"version":1,"created":1299207348},"services":[],"runningInstances":1}
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 19:46:19 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 251
8
+
9
+ [{"resources":{"memory":128},"uris":["r.vcap.me"],"staging":{"stack":"ruby redis_sample.rb","model":"http://b20nine.com/unknown"},"state":"STARTED","instances":1,"name":"r","meta":{"version":1,"created":1298681379},"services":[],"runningInstances":1}]
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 400 Bad Request
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 23:37:51 GMT
4
+ Content-Type: text/html;charset=utf-8
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 157
8
+
9
+ {"code":10050,"description":"Invalid number of instances: \"'', App instances not presentApp instances is not a numberInstances must be between 1 and 100\""}
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 204
2
+ Server: nginx/0.7.65
3
+ Date: Fri, 04 Mar 2011 00:07:10 GMT
4
+ Content-Type: text/html;charset=utf-8
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Location: http://api.vcap.me/apps/foo
8
+ Content-Length: 0
9
+
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 20:20:15 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 381
8
+
9
+ {"key-value":{"redis":{"2":{"type":"key-value","tiers":{"free":{"order":1,"description":"Free offering (64MiB)"}},"version":"2","vendor":"redis","description":"Redis key-value store service"}}},"database":{"mysql":{"5.1":{"type":"database","tiers":{"free":{"order":1,"description":"Free offering (1GiB)"}},"version":"5.1","description":"MySQL database service","vendor":"mysql"}}}}
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 302 Moved Temporarily
2
+ Server: nginx/0.7.65
3
+ Date: Fri, 04 Mar 2011 00:07:10 GMT
4
+ Content-Type: text/html;charset=utf-8
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Location: http://api.vcap.me/apps/foo
8
+ Content-Length: 0
9
+
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 302 Moved Temporarily
2
+ Server: nginx/0.7.65
3
+ Date: Fri, 04 Mar 2011 02:15:55 GMT
4
+ Content-Type: text/html;charset=utf-8
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Location: http://api.vcap.me/services/redis-86b7a8655555
8
+ Content-Length: 0
9
+
@@ -0,0 +1,27 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 19:25:34 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 380
8
+
9
+ {
10
+ "name": "vcap",
11
+ "build": "3465a13ab528443f1afcd3c9c2861a078549b8e5",
12
+ "support": "ac-support@vmware.com",
13
+ "version": 0.999,
14
+ "limits": {
15
+ "apps": 50,
16
+ "memory": 8192,
17
+ "app_uris": 4,
18
+ "services": 4
19
+ },
20
+ "user": "derek@gmail.com",
21
+ "description": "VMware's Cloud Application Platform",
22
+ "usage": {
23
+ "apps": 1,
24
+ "memory": 128,
25
+ "services": 0
26
+ }
27
+ }
@@ -0,0 +1,15 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 19:04:04 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 189
8
+
9
+ {
10
+ "name": "vcap",
11
+ "build": "3465a13ab528443f1afcd3c9c2861a078549b8e5",
12
+ "support": "ac-support@vmware.com",
13
+ "version": 0.999,
14
+ "description": "VMware's Cloud Application Platform"
15
+ }
@@ -0,0 +1,16 @@
1
+ HTTP/1.1 301 Moved Permanently
2
+ Location: http://www.google.com/
3
+ Content-Type: text/html; charset=UTF-8
4
+ Date: Thu, 03 Mar 2011 19:06:04 GMT
5
+ Expires: Sat, 02 Apr 2011 19:06:04 GMT
6
+ Cache-Control: public, max-age=2592000
7
+ Server: gws
8
+ Content-Length: 219
9
+ X-XSS-Protection: 1; mode=block
10
+
11
+ <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
12
+ <TITLE>301 Moved</TITLE></HEAD><BODY>
13
+ <H1>301 Moved</H1>
14
+ The document has moved
15
+ <A HREF="http://www.google.com/">here</A>.
16
+ </BODY></HTML>
@@ -0,0 +1,13 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Sun, 22 May 2011 18:58:41 GMT
4
+ Content-Type: application/json; charset=utf-8
5
+ Transfer-Encoding: chunked
6
+ Connection: keep-alive
7
+ Keep-Alive: timeout=20
8
+ ETag: "eb21ee2635a8b6b378f896e26b61f006"
9
+ Cache-Control: max-age=0, private, must-revalidate
10
+ X-UA-Compatible: IE=Edge
11
+ Content-Length: 365
12
+
13
+ [{"email":"test@example.com","admin":true,"apps":[{"name":"chat","state":"STARTED"},{"name":"smith","state":"STARTED"},{"name":"env","state":"STARTED"},{"name":"redirect","state":"STARTED"}]},{"email":"user2@example.com","admin":false,"apps":[]},{"email":"autotest@adamgreenfield.com","admin":false,"apps":[]},{"email":"user3@example.com","admin":false,"apps":[]}]
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 403 Forbidden
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 18:29:40 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 43
8
+
9
+ {"code":2002,"description":"Invalid token"}
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 18:26:45 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 112
8
+
9
+ {"token":"04085b082214646572656b40676d61696c2e636f6d6c2b07e517794d22198e59d96b40ccbc3625964dfb8dcca21174835d7e"}
@@ -0,0 +1 @@
1
+ 04085b082214646572656b40676d61696c2e636f6d6c2b07f014794d2219b3dd205faeaefc0a8c70bb3ba786628c8cb8d667
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 400 Bad Request
2
+ Server: nginx/0.7.65
3
+ Date: Fri, 04 Mar 2011 02:19:28 GMT
4
+ Content-Type: text/html;charset=utf-8
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 93
8
+
9
+ {"code":20001,"description":"A service with the name: \"redis-86b7a8655555\" already exists"}
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 21:46:29 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 313
8
+
9
+ [{"type":"key-value","vendor":"redis","version":"2","options":{"name":"redis-83ddf593-0690-4856-baba-24cc7ad9b1b0","port":6148,"node_id":"redis_node_1","hostname":"127.0.0.1","password":"2167d1f8-c251-46a8-8eed-7d390ab74757"},"tier":"free","name":"redis-7ed7da9","meta":{"version":1,"created":1299188448},"id":3}]
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 404 Not Found
2
+ Server: nginx/0.7.65
3
+ Date: Fri, 04 Mar 2011 02:26:39 GMT
4
+ Content-Type: text/html;charset=utf-8
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 75
8
+
9
+ {"code":21100,"description":"Service provision call failed due to timeout"}
@@ -0,0 +1,9 @@
1
+ HTTP/1.1 200 OK
2
+ Server: nginx/0.7.65
3
+ Date: Thu, 03 Mar 2011 19:38:32 GMT
4
+ Content-Type: application/json
5
+ Connection: keep-alive
6
+ Keep-Alive: timeout=20
7
+ Content-Length: 69
8
+
9
+ {"meta":{"version":1,"created":1298681367},"email":"derek@gmail.com"}
@@ -0,0 +1,11 @@
1
+
2
+ $:.unshift('./lib')
3
+ require 'vmc'
4
+ require 'cli'
5
+
6
+ require 'spec'
7
+ require 'webmock/rspec'
8
+
9
+ def spec_asset(filename)
10
+ File.expand_path(File.join(File.dirname(__FILE__), "assets", filename))
11
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'VMC::Cli::Runner' do
4
+
5
+ it 'should parse email and password correctly' do
6
+ args = "--email derek@gmail.com --password foo"
7
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
8
+ cli.options.should have(3).items
9
+ cli.options.should have_key :email
10
+ cli.options[:email].should == 'derek@gmail.com'
11
+ cli.options[:password].should == 'foo'
12
+ end
13
+
14
+ it 'should parse multiple variations of password' do
15
+ args = "--password foo"
16
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
17
+ cli.options[:password].should == 'foo'
18
+
19
+ args = "--pass foo"
20
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
21
+ cli.options[:password].should == 'foo'
22
+
23
+ args = "--passwd foo"
24
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
25
+ cli.options[:password].should == 'foo'
26
+ end
27
+
28
+ it 'should parse name and bind args correctly' do
29
+ args = "--name foo --bind bar"
30
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
31
+ cli.options[:name].should == 'foo'
32
+ cli.options[:bind].should == 'bar'
33
+ end
34
+
35
+ it 'should parse instances and instance into a number and string' do
36
+ args = "--instances 1 --instance 2"
37
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
38
+ cli.options[:instances].should == 1
39
+ cli.options[:instance].should == "2"
40
+ end
41
+
42
+ it 'should parse url, mem, path correctly' do
43
+ args = "--mem 64 --url http://foo.vcap.me --path ~derek"
44
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
45
+ cli.options[:mem].should == '64'
46
+ cli.options[:url].should == 'http://foo.vcap.me'
47
+ cli.options[:path].should == '~derek'
48
+ end
49
+
50
+ it 'should parse multiple forms of nostart correctly' do
51
+ cli = VMC::Cli::Runner.new().parse_options!
52
+ cli.options[:nostart].should_not be
53
+ args = "--nostart"
54
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
55
+ cli.options[:nostart].should be_true
56
+ args = "--no-start"
57
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
58
+ cli.options[:nostart].should be_true
59
+ end
60
+
61
+ it 'should parse force and all correctly' do
62
+ args = "--force --all"
63
+ cli = VMC::Cli::Runner.new(args.split).parse_options!
64
+ cli.options[:force].should be_true
65
+ cli.options[:all].should be_true
66
+ end
67
+
68
+ end
@@ -0,0 +1,332 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'VMC::Client' do
4
+ include WebMock::API
5
+
6
+ before(:all) do
7
+ @target = VMC::DEFAULT_TARGET
8
+ @local_target = VMC::DEFAULT_LOCAL_TARGET
9
+ @user = 'derek@gmail.com'
10
+ @password = 'foo'
11
+ @auth_token = spec_asset('sample_token.txt')
12
+ end
13
+
14
+ before(:each) do
15
+ # make sure these get cleared so we don't have tests pass that shouldn't
16
+ RestClient.proxy = nil
17
+ ENV['http_proxy'] = nil
18
+ ENV['https_proxy'] = nil
19
+ end
20
+
21
+ it 'should report its version' do
22
+ VMC::Client.version.should =~ /\d.\d.\d/
23
+ end
24
+
25
+ it 'should default to local target' do
26
+ client = VMC::Client.new
27
+ client.target.should == VMC::DEFAULT_TARGET
28
+ end
29
+
30
+ it 'should default to use secure protocol' do
31
+ client = VMC::Client.new
32
+ client.target.match(/^https/)
33
+ end
34
+
35
+ it 'should normalize target with no scheme' do
36
+ client = VMC::Client.new('api.cloudfoundry.com')
37
+ client.target.should == 'http://api.cloudfoundry.com'
38
+ end
39
+
40
+ it 'should properly initialize with auth_token' do
41
+ client = VMC::Client.new(@target, @auth_token)
42
+ client.target.should == @target
43
+ client.auth_token.should == @auth_token
44
+ end
45
+
46
+ it 'should allow login correctly and return an auth_token' do
47
+ login_path = "#{@local_target}/users/#{@user}/tokens"
48
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
49
+ client = VMC::Client.new(@local_target)
50
+ auth_token = client.login(@user, @password)
51
+ client.target.should == @local_target
52
+ client.user.should == @user
53
+ client.auth_token.should be
54
+ auth_token.should be
55
+ auth_token.should == client.auth_token
56
+ end
57
+
58
+ it 'should raise exception if login fails' do
59
+ login_path = "#{@local_target}/users/#{@user}/tokens"
60
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_fail.txt')))
61
+ client = VMC::Client.new(@local_target)
62
+ expect { client.login(@user, @password) }.to raise_error(VMC::Client::TargetError)
63
+ end
64
+
65
+ it 'should allow admin users to proxy for others' do
66
+ proxy = 'vadim@gmail.com'
67
+ client = VMC::Client.new(@target)
68
+ client.proxy_for(proxy)
69
+ client.proxy.should == proxy
70
+ end
71
+
72
+ it 'should properly get info for valid target cloud' do
73
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
74
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return.txt')))
75
+ client = VMC::Client.new(@local_target)
76
+ info = client.info
77
+ a_request(:get, info_path).should have_been_made.once
78
+ info.should have_key :support
79
+ info.should have_key :description
80
+ info.should have_key :name
81
+ info.should have_key :version
82
+ info.should have_key :build
83
+ end
84
+
85
+ it 'should raise and exception for a bad target' do
86
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
87
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return_bad.txt')))
88
+ client = VMC::Client.new(@local_target)
89
+ expect {info = client.info}.to raise_error(VMC::Client::BadResponse)
90
+ a_request(:get, info_path).should have_been_made.once
91
+ end
92
+
93
+ it 'should have target_valid? return true for a good target' do
94
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
95
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return.txt')))
96
+ client = VMC::Client.new(@local_target)
97
+ client.target_valid?.should be_true
98
+ end
99
+
100
+ it 'should have target_valid? return false for a bad target' do
101
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
102
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return_bad.txt')))
103
+ client = VMC::Client.new(@local_target)
104
+ client.target_valid?.should be_false
105
+ end
106
+
107
+ it 'should respond ok if properly logged in' do
108
+ login_path = "#{@local_target}/users/#{@user}/tokens"
109
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
110
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
111
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
112
+ client = VMC::Client.new(@local_target)
113
+ client.login(@user, @password)
114
+ client.logged_in?.should be_true
115
+ end
116
+
117
+ it 'should fail when trying to change password unless logged in' do
118
+ login_path = "#{@local_target}/users/#{@user}/tokens"
119
+ stub_request(:post, login_path).to_return(File.new(spec_asset('login_success.txt')))
120
+ user_info_path = "#{@local_target}/users/#{@user}"
121
+ stub_request(:get, user_info_path).to_return(File.new(spec_asset('user_info.txt')))
122
+ stub_request(:put, user_info_path)
123
+ client = VMC::Client.new(@local_target)
124
+ client.login(@user, @password)
125
+ client.change_password('bar')
126
+ end
127
+
128
+ it 'should get a proper list of apps' do
129
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
130
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
131
+ apps_path = "#{@local_target}#{VMC::APPS_PATH}"
132
+ stub_request(:get, apps_path).to_return(File.new(spec_asset('app_listings.txt')))
133
+ client = VMC::Client.new(@local_target, @auth_token)
134
+ apps = client.apps
135
+ apps.should have(1).items
136
+ app = apps.first
137
+ app.should have_key :state
138
+ app.should have_key :uris
139
+ app.should have_key :name
140
+ app.should have_key :services
141
+ app.should have_key :instances
142
+ end
143
+
144
+ it 'should get a proper list of users' do
145
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
146
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
147
+ users_path = "#{@local_target}#{VMC::USERS_PATH}"
148
+ stub_request(:get, users_path).to_return(File.new(spec_asset('list_users.txt')))
149
+ client = VMC::Client.new(@local_target, @auth_token)
150
+ users = client.users
151
+ users.should have(4).items
152
+ user = users.first
153
+ user.should have_key :email
154
+ user.should have_key :admin
155
+ user.should have_key :apps
156
+ end
157
+
158
+ it 'should get a proper list of services' do
159
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
160
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
161
+ services_path = "#{@local_target}#{VMC::GLOBAL_SERVICES_PATH}"
162
+ stub_request(:get, services_path).to_return(File.new(spec_asset('global_service_listings.txt')))
163
+ client = VMC::Client.new(@local_target, @auth_token)
164
+ services = client.services_info
165
+ services.should have(2).items
166
+ # FIXME, add in more details.
167
+ end
168
+
169
+ it 'should get a proper list of provisioned services' do
170
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
171
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
172
+ services_path = "#{@local_target}#{VMC::SERVICES_PATH}"
173
+ stub_request(:get, services_path).to_return(File.new(spec_asset('service_listings.txt')))
174
+ client = VMC::Client.new(@local_target, @auth_token)
175
+ app_services = client.services
176
+ app_services.should have(1).items
177
+ redis = app_services.first
178
+ redis.should have_key :type
179
+ redis.should have_key :vendor
180
+ end
181
+
182
+ it 'should raise when trying to create an app with no manifest' do
183
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
184
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
185
+ app_path = "#{@local_target}#{VMC::APPS_PATH}"
186
+ stub_request(:post, app_path).to_return(File.new(spec_asset('bad_create_app.txt')))
187
+ client = VMC::Client.new(@local_target, @auth_token)
188
+ expect { client.create_app('foo') }.to raise_error(VMC::Client::NotFound)
189
+ end
190
+
191
+ it 'should create an app with a simple manifest' do
192
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
193
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
194
+ app_path = "#{@local_target}#{VMC::APPS_PATH}"
195
+ stub_request(:post, app_path).to_return(File.new(spec_asset('good_create_app.txt')))
196
+ client = VMC::Client.new(@local_target, @auth_token)
197
+ manifest = {
198
+ :name => 'foo',
199
+ :uris => ['foo.vcap.me'],
200
+ :instances => 1,
201
+ :staging => { :model => 'nodejs/1.0' },
202
+ :resources => { :memory => 64 }
203
+ }
204
+ client.create_app('foo', manifest)
205
+ end
206
+
207
+ it 'should allow us to delete an app we created' do
208
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
209
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
210
+ app_path = "#{@local_target}#{VMC::APPS_PATH}/foo"
211
+ stub_request(:delete, app_path).to_return(File.new(spec_asset('delete_app.txt')))
212
+ client = VMC::Client.new(@local_target, @auth_token)
213
+ client.delete_app('foo')
214
+ end
215
+
216
+ it 'should provision a service' do
217
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
218
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
219
+ global_services_path = "#{@local_target}#{VMC::GLOBAL_SERVICES_PATH}"
220
+ stub_request(:get, global_services_path).to_return(File.new(spec_asset('global_service_listings.txt')))
221
+ services_path = "#{@local_target}#{VMC::SERVICES_PATH}"
222
+ stub_request(:post, services_path).to_return(File.new(spec_asset('good_create_service.txt')))
223
+ client = VMC::Client.new(@local_target, @auth_token)
224
+ client.create_service('redis', 'foo')
225
+ end
226
+
227
+ it 'should complain if we try to provision a service that already exists with same name' do
228
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
229
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
230
+ global_services_path = "#{@local_target}#{VMC::GLOBAL_SERVICES_PATH}"
231
+ stub_request(:get, global_services_path).to_return(File.new(spec_asset('global_service_listings.txt')))
232
+ services_path = "#{@local_target}#{VMC::SERVICES_PATH}"
233
+ stub_request(:post, services_path).to_return(File.new(spec_asset('service_already_exists.txt')))
234
+ client = VMC::Client.new(@local_target, @auth_token)
235
+ expect { client.create_service('redis', 'foo') }.to raise_error(VMC::Client::NotFound)
236
+ end
237
+
238
+ it 'should complain if we try to provision a service that does not exist' do
239
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
240
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
241
+ global_services_path = "#{@local_target}#{VMC::GLOBAL_SERVICES_PATH}"
242
+ stub_request(:get, global_services_path).to_return(File.new(spec_asset('global_service_listings.txt')))
243
+ services_path = "#{@local_target}#{VMC::SERVICES_PATH}"
244
+ stub_request(:post, services_path).to_return(File.new(spec_asset('service_not_found.txt')))
245
+ client = VMC::Client.new(@local_target, @auth_token)
246
+ expect { client.create_service('redis', 'foo') }.to raise_error(VMC::Client::NotFound)
247
+ end
248
+
249
+ it 'should allow us to delete a provisioned service' do
250
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
251
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
252
+ services_path = "#{@local_target}#{VMC::SERVICES_PATH}"
253
+ stub_request(:get, services_path).to_return(File.new(spec_asset('service_listings.txt')))
254
+ services_path = "#{@local_target}#{VMC::SERVICES_PATH}/redis-7ed7da9"
255
+ stub_request(:delete, services_path)
256
+ client = VMC::Client.new(@local_target, @auth_token)
257
+ client.delete_service('redis-7ed7da9')
258
+ end
259
+
260
+ it 'should bind a service to an app' do
261
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
262
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
263
+ app_path = "#{@local_target}#{VMC::APPS_PATH}/foo"
264
+ stub_request(:get, app_path).to_return(File.new(spec_asset('app_info.txt')))
265
+ stub_request(:put, app_path)
266
+ client = VMC::Client.new(@local_target, @auth_token)
267
+ client.bind_service('my-redis', 'foo')
268
+ a_request(:get, app_path).should have_been_made.once
269
+ a_request(:put, app_path).should have_been_made.once
270
+ end
271
+
272
+ it 'should unbind an existing service from an app' do
273
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
274
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_authenticated.txt')))
275
+ app_path = "#{@local_target}#{VMC::APPS_PATH}/foo"
276
+ stub_request(:get, app_path).to_return(File.new(spec_asset('app_info.txt')))
277
+ stub_request(:put, app_path)
278
+ client = VMC::Client.new(@local_target, @auth_token)
279
+ client.unbind_service('my-redis', 'foo')
280
+ a_request(:get, app_path).should have_been_made.once
281
+ a_request(:put, app_path).should have_been_made.once
282
+ end
283
+
284
+ it 'should set a proxy if one is set' do
285
+ target = "http://nonlocal.domain.com"
286
+ info_path = "#{target}#{VMC::INFO_PATH}"
287
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return.txt')))
288
+ proxy = 'http://proxy.vmware.com:3128'
289
+ ENV['http_proxy'] = proxy
290
+ client = VMC::Client.new(target)
291
+ info = client.info
292
+ RestClient.proxy.should == proxy
293
+ end
294
+
295
+ it 'should not set a proxy when accessing localhost' do
296
+ info_path = "#{@local_target}#{VMC::INFO_PATH}"
297
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return.txt')))
298
+ proxy = 'http://proxy.vmware.com:3128'
299
+ ENV['http_proxy'] = proxy
300
+ client = VMC::Client.new(@local_target)
301
+ info = client.info
302
+ RestClient.proxy.should == nil
303
+ end
304
+
305
+ it 'should use a secure proxy over a normal proxy if one is set' do
306
+ info_path = "#{@target}#{VMC::INFO_PATH}"
307
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return.txt')))
308
+ proxy = 'http://proxy.vmware.com:3128'
309
+ secure_proxy = 'http://secure-proxy.vmware.com:3128'
310
+ ENV['http_proxy'] = proxy
311
+ ENV['https_proxy'] = secure_proxy
312
+ client = VMC::Client.new(@target)
313
+ info = client.info
314
+ RestClient.proxy.should == secure_proxy
315
+ end
316
+
317
+ it 'should not use a secure proxy for non-secure site' do
318
+ target = "http://nonlocal.domain.com"
319
+ info_path = "#{target}#{VMC::INFO_PATH}"
320
+ stub_request(:get, info_path).to_return(File.new(spec_asset('info_return.txt')))
321
+ proxy = 'http://proxy.vmware.com:3128'
322
+ secure_proxy = 'http://secure-proxy.vmware.com:3128'
323
+ ENV['http_proxy'] = proxy
324
+ ENV['https_proxy'] = secure_proxy
325
+ client = VMC::Client.new(target)
326
+ info = client.info
327
+ RestClient.proxy.should == proxy
328
+ end
329
+
330
+ # WebMock.allow_net_connect!
331
+
332
+ end