af 0.3.12

Sign up to get free protection for your applications and to get access to all the features.
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