new_cfoundry 4.8.2

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 (269) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +11 -0
  8. data/Checkfile +2 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE +987 -0
  11. data/NOTICE +10 -0
  12. data/README.md +9 -0
  13. data/Rakefile +14 -0
  14. data/VERSION +1 -0
  15. data/cfoundry.gemspec +40 -0
  16. data/config/locales/en.yml +168 -0
  17. data/lib/cc_api_stub/app_usage_events.rb +11 -0
  18. data/lib/cc_api_stub/applications.rb +57 -0
  19. data/lib/cc_api_stub/domains.rb +32 -0
  20. data/lib/cc_api_stub/events.rb +11 -0
  21. data/lib/cc_api_stub/frameworks.rb +22 -0
  22. data/lib/cc_api_stub/helper.rb +148 -0
  23. data/lib/cc_api_stub/login.rb +21 -0
  24. data/lib/cc_api_stub/organization_users.rb +27 -0
  25. data/lib/cc_api_stub/organizations.rb +82 -0
  26. data/lib/cc_api_stub/routes.rb +26 -0
  27. data/lib/cc_api_stub/runtimes.rb +22 -0
  28. data/lib/cc_api_stub/service_bindings.rb +22 -0
  29. data/lib/cc_api_stub/service_instances.rb +22 -0
  30. data/lib/cc_api_stub/services.rb +21 -0
  31. data/lib/cc_api_stub/space_users.rb +27 -0
  32. data/lib/cc_api_stub/spaces.rb +58 -0
  33. data/lib/cc_api_stub/users.rb +85 -0
  34. data/lib/cc_api_stub.rb +20 -0
  35. data/lib/cfoundry/auth_token.rb +63 -0
  36. data/lib/cfoundry/baseclient.rb +216 -0
  37. data/lib/cfoundry/chatty_hash.rb +46 -0
  38. data/lib/cfoundry/client.rb +42 -0
  39. data/lib/cfoundry/concerns/login_helpers.rb +14 -0
  40. data/lib/cfoundry/concerns/proxy_options.rb +17 -0
  41. data/lib/cfoundry/errors.rb +163 -0
  42. data/lib/cfoundry/rest_client.rb +317 -0
  43. data/lib/cfoundry/test_support.rb +3 -0
  44. data/lib/cfoundry/trace_helpers.rb +64 -0
  45. data/lib/cfoundry/uaaclient.rb +160 -0
  46. data/lib/cfoundry/upload_helpers.rb +222 -0
  47. data/lib/cfoundry/v2/app.rb +303 -0
  48. data/lib/cfoundry/v2/app_event.rb +13 -0
  49. data/lib/cfoundry/v2/app_instance.rb +74 -0
  50. data/lib/cfoundry/v2/app_usage_event.rb +14 -0
  51. data/lib/cfoundry/v2/base.rb +108 -0
  52. data/lib/cfoundry/v2/client.rb +104 -0
  53. data/lib/cfoundry/v2/domain.rb +20 -0
  54. data/lib/cfoundry/v2/event.rb +17 -0
  55. data/lib/cfoundry/v2/helper.rb +11 -0
  56. data/lib/cfoundry/v2/managed_service_instance.rb +12 -0
  57. data/lib/cfoundry/v2/model.rb +211 -0
  58. data/lib/cfoundry/v2/model_magic/attribute.rb +49 -0
  59. data/lib/cfoundry/v2/model_magic/client_extensions.rb +170 -0
  60. data/lib/cfoundry/v2/model_magic/has_summary.rb +49 -0
  61. data/lib/cfoundry/v2/model_magic/query_multi_value_helper.rb +21 -0
  62. data/lib/cfoundry/v2/model_magic/query_value_helper.rb +33 -0
  63. data/lib/cfoundry/v2/model_magic/queryable_by.rb +39 -0
  64. data/lib/cfoundry/v2/model_magic/to_many.rb +138 -0
  65. data/lib/cfoundry/v2/model_magic/to_one.rb +81 -0
  66. data/lib/cfoundry/v2/model_magic.rb +134 -0
  67. data/lib/cfoundry/v2/organization.rb +44 -0
  68. data/lib/cfoundry/v2/quota_definition.rb +12 -0
  69. data/lib/cfoundry/v2/route.rb +25 -0
  70. data/lib/cfoundry/v2/service.rb +22 -0
  71. data/lib/cfoundry/v2/service_auth_token.rb +9 -0
  72. data/lib/cfoundry/v2/service_binding.rb +10 -0
  73. data/lib/cfoundry/v2/service_broker.rb +12 -0
  74. data/lib/cfoundry/v2/service_instance.rb +14 -0
  75. data/lib/cfoundry/v2/service_plan.rb +16 -0
  76. data/lib/cfoundry/v2/space.rb +30 -0
  77. data/lib/cfoundry/v2/stack.rb +10 -0
  78. data/lib/cfoundry/v2/user.rb +93 -0
  79. data/lib/cfoundry/v2/user_provided_service_instance.rb +15 -0
  80. data/lib/cfoundry/validator.rb +41 -0
  81. data/lib/cfoundry/version.rb +4 -0
  82. data/lib/cfoundry/zip.rb +56 -0
  83. data/lib/cfoundry.rb +5 -0
  84. data/release_notes/release_1_5_3.md +177 -0
  85. data/release_notes/release_2.3.1.md +14 -0
  86. data/release_notes/release_2.3.3.md +38 -0
  87. data/release_notes/release_2.3.4.md +16 -0
  88. data/release_notes/release_2.3.5.md +14 -0
  89. data/release_notes/release_2.3.6.md +14 -0
  90. data/release_notes/release_2.3.6.rc1.md +29 -0
  91. data/release_notes/release_2.3.6.rc2.md +19 -0
  92. data/release_notes/release_2.3.7.rc1.md +14 -0
  93. data/release_notes/release_2.4.0.md +41 -0
  94. data/release_notes/release_2.4.1.rc1.md +58 -0
  95. data/release_notes/release_3.0.0.md +21 -0
  96. data/release_notes/release_3.0.1.md +16 -0
  97. data/release_notes/release_3.0.2.rc1.md +19 -0
  98. data/release_notes/release_4.0.0.md +19 -0
  99. data/release_notes/release_4.0.1.md +14 -0
  100. data/release_notes/release_4.0.2.rc1.md +14 -0
  101. data/release_notes/release_4.0.2.rc2.md +11 -0
  102. data/release_notes/release_4.0.2.rc3.md +11 -0
  103. data/release_notes/release_4.0.2.rc4.md +19 -0
  104. data/release_notes/release_4.0.2.rc5.md +14 -0
  105. data/release_notes/release_4.0.3.md +19 -0
  106. data/release_notes/release_4.0.4.rc1.md +14 -0
  107. data/release_notes/release_4.0.4.rc2.md +14 -0
  108. data/release_notes/release_4.1.0.md +19 -0
  109. data/release_notes/release_4.2.0.rc.md +24 -0
  110. data/release_notes/release_4.3.0.md +22 -0
  111. data/release_notes/release_4.3.1.md +14 -0
  112. data/release_notes/release_4.3.10.md +14 -0
  113. data/release_notes/release_4.3.11.md +14 -0
  114. data/release_notes/release_4.3.12.md +14 -0
  115. data/release_notes/release_4.3.2.rc1.md +21 -0
  116. data/release_notes/release_4.3.3.md +24 -0
  117. data/release_notes/release_4.3.4.md +11 -0
  118. data/release_notes/release_4.3.4.rc1.md +24 -0
  119. data/release_notes/release_4.3.5.md +36 -0
  120. data/release_notes/release_4.3.5.rc1.md +21 -0
  121. data/release_notes/release_4.3.6.md +14 -0
  122. data/release_notes/release_4.3.7.md +50 -0
  123. data/release_notes/release_4.3.8.md +19 -0
  124. data/release_notes/release_4.3.9.md +14 -0
  125. data/release_notes/release_4.4.0.md +16 -0
  126. data/release_notes/release_4.5.1.md +11 -0
  127. data/release_notes/release_4.5.2.md +14 -0
  128. data/release_notes/release_4.5.3.md +29 -0
  129. data/release_notes/release_4.6.0.md +24 -0
  130. data/release_notes/release_4.6.1.md +14 -0
  131. data/release_notes/release_4.6.2.md +16 -0
  132. data/release_notes/release_4.6.3.rc1.md +14 -0
  133. data/release_notes/release_4.6.3.rc2.md +14 -0
  134. data/release_notes/release_4.6.3.rc3.md +17 -0
  135. data/release_notes/release_4.7.0.md +11 -0
  136. data/release_notes/release_4.7.1.md +14 -0
  137. data/release_notes/release_4.7.1.rc.1.md +14 -0
  138. data/release_notes/release_4.7.1.rc1.md +19 -0
  139. data/script/gpp +3 -0
  140. data/spec/cc_api_stub/app_usage_events_spec.rb +12 -0
  141. data/spec/cc_api_stub/applications_spec.rb +69 -0
  142. data/spec/cc_api_stub/domains_spec.rb +40 -0
  143. data/spec/cc_api_stub/events_spec.rb +12 -0
  144. data/spec/cc_api_stub/frameworks_spec.rb +19 -0
  145. data/spec/cc_api_stub/login_spec.rb +20 -0
  146. data/spec/cc_api_stub/organization_users_spec.rb +35 -0
  147. data/spec/cc_api_stub/organizations_spec.rb +118 -0
  148. data/spec/cc_api_stub/routes_spec.rb +19 -0
  149. data/spec/cc_api_stub/runtimes_spec.rb +19 -0
  150. data/spec/cc_api_stub/service_bindings_spec.rb +13 -0
  151. data/spec/cc_api_stub/service_instances_spec.rb +19 -0
  152. data/spec/cc_api_stub/services_spec.rb +11 -0
  153. data/spec/cc_api_stub/space_users_spec.rb +35 -0
  154. data/spec/cc_api_stub/spaces_spec.rb +38 -0
  155. data/spec/cc_api_stub/users_spec.rb +107 -0
  156. data/spec/cfoundry/auth_token_spec.rb +154 -0
  157. data/spec/cfoundry/baseclient_spec.rb +298 -0
  158. data/spec/cfoundry/client_spec.rb +13 -0
  159. data/spec/cfoundry/errors_spec.rb +117 -0
  160. data/spec/cfoundry/rest_client_spec.rb +349 -0
  161. data/spec/cfoundry/trace_helpers_spec.rb +91 -0
  162. data/spec/cfoundry/uaaclient_spec.rb +435 -0
  163. data/spec/cfoundry/upload_helpers_spec.rb +182 -0
  164. data/spec/cfoundry/v2/app_event_spec.rb +97 -0
  165. data/spec/cfoundry/v2/app_instance_spec.rb +31 -0
  166. data/spec/cfoundry/v2/app_spec.rb +354 -0
  167. data/spec/cfoundry/v2/app_usage_event_spec.rb +15 -0
  168. data/spec/cfoundry/v2/base_spec.rb +375 -0
  169. data/spec/cfoundry/v2/client_spec.rb +121 -0
  170. data/spec/cfoundry/v2/domain_spec.rb +63 -0
  171. data/spec/cfoundry/v2/event_spec.rb +15 -0
  172. data/spec/cfoundry/v2/managed_service_instance_spec.rb +149 -0
  173. data/spec/cfoundry/v2/model_magic/attribute_spec.rb +123 -0
  174. data/spec/cfoundry/v2/model_magic/has_summary_spec.rb +17 -0
  175. data/spec/cfoundry/v2/model_magic/to_many_spec.rb +53 -0
  176. data/spec/cfoundry/v2/model_magic/to_one_spec.rb +106 -0
  177. data/spec/cfoundry/v2/model_magic_spec.rb +43 -0
  178. data/spec/cfoundry/v2/model_spec.rb +434 -0
  179. data/spec/cfoundry/v2/organization_spec.rb +135 -0
  180. data/spec/cfoundry/v2/quota_definition_spec.rb +50 -0
  181. data/spec/cfoundry/v2/route_spec.rb +42 -0
  182. data/spec/cfoundry/v2/service_plan_spec.rb +53 -0
  183. data/spec/cfoundry/v2/service_spec.rb +58 -0
  184. data/spec/cfoundry/v2/space_spec.rb +13 -0
  185. data/spec/cfoundry/v2/user_provided_service_instance_spec.rb +57 -0
  186. data/spec/cfoundry/v2/user_spec.rb +206 -0
  187. data/spec/cfoundry/validator_spec.rb +94 -0
  188. data/spec/factories/app_events_factory.rb +7 -0
  189. data/spec/factories/app_usage_events_factory.rb +32 -0
  190. data/spec/factories/apps_factory.rb +11 -0
  191. data/spec/factories/clients_factory.rb +7 -0
  192. data/spec/factories/domains_factory.rb +10 -0
  193. data/spec/factories/events_factory.rb +50 -0
  194. data/spec/factories/organizations_factory.rb +12 -0
  195. data/spec/factories/quota_definitions_factory.rb +8 -0
  196. data/spec/factories/routes_factory.rb +10 -0
  197. data/spec/factories/service_instances_factory.rb +10 -0
  198. data/spec/factories/service_plans_factory.rb +10 -0
  199. data/spec/factories/services_factory.rb +10 -0
  200. data/spec/factories/spaces_factory.rb +10 -0
  201. data/spec/factories/user_provided_service_instances_factory.rb +10 -0
  202. data/spec/factories/users_factory.rb +10 -0
  203. data/spec/fixtures/apps/with_cfignore/.cfignore +4 -0
  204. data/spec/fixtures/apps/with_cfignore/.hidden_file +1 -0
  205. data/spec/fixtures/apps/with_cfignore/ambiguous_ignored +0 -0
  206. data/spec/fixtures/apps/with_cfignore/ignored_dir/file_in_ignored_dir.txt +1 -0
  207. data/spec/fixtures/apps/with_cfignore/ignored_file.txt +1 -0
  208. data/spec/fixtures/apps/with_cfignore/non_ignored_dir/file_in_non_ignored_dir.txt +1 -0
  209. data/spec/fixtures/apps/with_cfignore/non_ignored_dir/ignored_file.txt +1 -0
  210. data/spec/fixtures/apps/with_cfignore/non_ignored_dir/toplevel_ignored.txt +0 -0
  211. data/spec/fixtures/apps/with_cfignore/non_ignored_file.txt +1 -0
  212. data/spec/fixtures/apps/with_cfignore/toplevel_ignored.txt +0 -0
  213. data/spec/fixtures/apps/with_dotfiles/.dotfile +1 -0
  214. data/spec/fixtures/apps/with_dotfiles/xyz +1 -0
  215. data/spec/fixtures/apps/with_external_symlink/foo +1 -0
  216. data/spec/fixtures/apps/with_ignored_external_symlink/.cfignore +1 -0
  217. data/spec/fixtures/apps/with_ignored_external_symlink/foo +1 -0
  218. data/spec/fixtures/apps/with_nested_directories/foo/bar/baz/fizz +0 -0
  219. data/spec/fixtures/apps/with_nested_directories/xyz +0 -0
  220. data/spec/fixtures/empty_file +0 -0
  221. data/spec/fixtures/fake_cc_app_usage_events.json +152 -0
  222. data/spec/fixtures/fake_cc_application.json +20 -0
  223. data/spec/fixtures/fake_cc_application_summary.json +56 -0
  224. data/spec/fixtures/fake_cc_created_application.json +11 -0
  225. data/spec/fixtures/fake_cc_created_domain.json +15 -0
  226. data/spec/fixtures/fake_cc_created_organization.json +11 -0
  227. data/spec/fixtures/fake_cc_created_route.json +13 -0
  228. data/spec/fixtures/fake_cc_created_service_instance.json +11 -0
  229. data/spec/fixtures/fake_cc_created_space.json +11 -0
  230. data/spec/fixtures/fake_cc_created_user.json +11 -0
  231. data/spec/fixtures/fake_cc_domain.json +55 -0
  232. data/spec/fixtures/fake_cc_domain_spaces.json +27 -0
  233. data/spec/fixtures/fake_cc_empty_search.json +7 -0
  234. data/spec/fixtures/fake_cc_events.json +419 -0
  235. data/spec/fixtures/fake_cc_frameworks.json +20 -0
  236. data/spec/fixtures/fake_cc_managed_service_instance.json +83 -0
  237. data/spec/fixtures/fake_cc_organization.json +161 -0
  238. data/spec/fixtures/fake_cc_organization_domains.json +59 -0
  239. data/spec/fixtures/fake_cc_organization_search.json +37 -0
  240. data/spec/fixtures/fake_cc_organization_spaces.json +99 -0
  241. data/spec/fixtures/fake_cc_organization_summary.json +20 -0
  242. data/spec/fixtures/fake_cc_organization_users.json +81 -0
  243. data/spec/fixtures/fake_cc_route.json +16 -0
  244. data/spec/fixtures/fake_cc_runtimes.json +20 -0
  245. data/spec/fixtures/fake_cc_service_binding.json +22 -0
  246. data/spec/fixtures/fake_cc_service_bindings.json +24 -0
  247. data/spec/fixtures/fake_cc_service_instance.json +83 -0
  248. data/spec/fixtures/fake_cc_service_instances.json +72 -0
  249. data/spec/fixtures/fake_cc_services.json +160 -0
  250. data/spec/fixtures/fake_cc_space.json +45 -0
  251. data/spec/fixtures/fake_cc_space_apps.json +49 -0
  252. data/spec/fixtures/fake_cc_space_summary.json +84 -0
  253. data/spec/fixtures/fake_cc_spaces.json +92 -0
  254. data/spec/fixtures/fake_cc_stats.json +29 -0
  255. data/spec/fixtures/fake_cc_user.json +139 -0
  256. data/spec/fixtures/fake_cc_user_organizations.json +92 -0
  257. data/spec/fixtures/fake_cc_user_provided_service_instance.json +51 -0
  258. data/spec/fixtures/fake_cc_user_with_managers.json +85 -0
  259. data/spec/integration/client_spec.rb +38 -0
  260. data/spec/spec_helper.rb +22 -0
  261. data/spec/support/factory_girl.rb +6 -0
  262. data/spec/support/shared_examples/cc_api_stub_request_examples.rb +79 -0
  263. data/spec/support/shared_examples/client_login_examples.rb +46 -0
  264. data/spec/support/shared_examples/model_summary_examples.rb +34 -0
  265. data/spec/support/test_model_builder.rb +10 -0
  266. data/vendor/errors/README.md +4 -0
  267. data/vendor/errors/v1.yml +189 -0
  268. data/vendor/errors/v2.yml +384 -0
  269. metadata +693 -0
@@ -0,0 +1,435 @@
1
+ require "spec_helper"
2
+
3
+ describe CFoundry::UAAClient do
4
+ let(:target) { "https://uaa.example.com" }
5
+ let(:uaa) { CFoundry::UAAClient.new(target) }
6
+ let(:auth_header) { "bearer access-token" }
7
+
8
+ before do
9
+ uaa.token = CFoundry::AuthToken.new(auth_header)
10
+ CF::UAA::Util.default_logger.level = 1
11
+ stub_request(:get, "#{target}/login").
12
+ to_return :status => 200, :headers => {'Content-Type' => 'application/json'},
13
+ :body => <<EOF
14
+ {
15
+ "timestamp": "2012-11-08T13:32:18+0000",
16
+ "commit_id": "ebbf817", "prompts": {}
17
+ }
18
+ EOF
19
+ end
20
+
21
+ shared_examples "UAA wrapper" do
22
+ it "converts UAA errors to CFoundry equivalents" do
23
+ expect(uaa).to receive(:wrap_uaa_errors) { nil }
24
+ subject
25
+ end
26
+ end
27
+
28
+ describe '#initialize' do
29
+ it "passes proxy info to the UAA info client" do
30
+ allow(CF::UAA::Info).to receive(:new)
31
+ CFoundry::UAAClient.new(target, 'cf', http_proxy: 'http-proxy.example.com', https_proxy: 'https-proxy.example.com')
32
+ expect(CF::UAA::Info).to have_received(:new).with(anything, hash_including(
33
+ http_proxy: 'http-proxy.example.com',
34
+ https_proxy: 'https-proxy.example.com'
35
+ ))
36
+ end
37
+ end
38
+
39
+ describe '#prompts' do
40
+ subject { uaa.prompts }
41
+
42
+ include_examples "UAA wrapper"
43
+
44
+ # GET (target)/login
45
+ it "receives the prompts from /login" do
46
+ stub_request(:get, "#{target}/login").to_return :status => 200,
47
+ :headers => {'Content-Type' => 'application/json'},
48
+ :body => <<EOF
49
+ {
50
+ "timestamp": "2012-11-08T13:32:18+0000",
51
+ "commit_id": "ebbf817",
52
+ "app": {
53
+ "version": "1.2.6",
54
+ "artifact": "cloudfoundry-identity-uaa",
55
+ "description": "User Account and Authentication Service",
56
+ "name": "UAA"
57
+ },
58
+ "prompts": {
59
+ "username": [
60
+ "text",
61
+ "Email"
62
+ ],
63
+ "password": [
64
+ "password",
65
+ "Password"
66
+ ]
67
+ }
68
+ }
69
+ EOF
70
+
71
+ expect(subject).to eq(
72
+ :username => ["text", "Email"],
73
+ :password => ["password", "Password"])
74
+ end
75
+ end
76
+
77
+ describe '#authorize' do
78
+ let(:username) { "foo@bar.com" }
79
+ let(:password) { "test" }
80
+ let(:creds) { {:username => username, :password => password} }
81
+ let(:state) { 'somestate' }
82
+ let(:redirect_uri) { 'https://uaa.example.com/redirect/cf' }
83
+ let(:auth) { Object.new }
84
+ let(:issuer) { Object.new }
85
+
86
+ subject { uaa.authorize(creds) }
87
+
88
+ before do
89
+ allow(issuer).to receive(:request_token) { auth }
90
+ allow(uaa).to receive(:token_issuer) { issuer }
91
+ end
92
+
93
+ include_examples "UAA wrapper"
94
+
95
+ it 'returns the token on successful authentication' do
96
+ expect(issuer)
97
+ .to receive(:request_token)
98
+ .with(:grant_type => "password",
99
+ :scope => nil,
100
+ :username => username,
101
+ :password => password) { auth }
102
+ expect(subject).to eq auth
103
+ end
104
+
105
+ context 'when authorization fails' do
106
+ context 'in the expected way' do
107
+ it 'raises a CFoundry::Denied error' do
108
+ expect(issuer).to receive(:request_token) { raise CF::UAA::BadResponse.new("401: FooBar") }
109
+ expect { subject }.to raise_error(CFoundry::Denied, "401: Authorization failed")
110
+ end
111
+ end
112
+
113
+
114
+ context 'in an unexpected way' do
115
+ it 'raises a CFoundry::Denied error' do
116
+ expect(issuer).to receive(:request_token) { raise CF::UAA::BadResponse.new("no_status_code") }
117
+ expect { subject }.to raise_error(CFoundry::Denied, "400: Authorization failed")
118
+ end
119
+ end
120
+
121
+ context "with a CF::UAA::TargetError" do
122
+ before { allow(issuer).to receive(:request_token) { raise CF::UAA::TargetError.new("useless info") } }
123
+
124
+ it "retries with implicit grant" do
125
+ expect(issuer).to receive(:implicit_grant_with_creds).with(:username => username, :password => password)
126
+ expect { subject }.to_not raise_error
127
+ end
128
+
129
+ it "fails with Denied when given a 401" do
130
+ allow(issuer).to receive(:implicit_grant_with_creds) { raise CF::UAA::BadResponse.new("status 401") }
131
+ expect { subject }.to raise_error(CFoundry::Denied, "401: Authorization failed")
132
+ end
133
+
134
+ it "fails with Denied when given any other status code" do
135
+ allow(issuer).to receive(:implicit_grant_with_creds) { raise CF::UAA::BadResponse.new("no status code") }
136
+ expect { subject }.to raise_error(CFoundry::Denied, "400: Authorization failed")
137
+ end
138
+ end
139
+ end
140
+ end
141
+
142
+ describe '#users' do
143
+ subject { uaa.users }
144
+
145
+ it 'requests /Users' do
146
+ stub_request(:get, "#{target}/Users").with(
147
+ :headers => { "authorization" => auth_header }
148
+ ).to_return(
149
+ :headers => {'Content-Type' => 'application/json'},
150
+ :body => '{ "resources": [] }'
151
+ )
152
+ expect(subject).to eq({:resources => []})
153
+ end
154
+
155
+ context "when there is no token" do
156
+ before { uaa.token = nil }
157
+
158
+ it "doesn't blow up" do
159
+ stub_request(:get, "#{target}/Users").to_return(
160
+ :headers => {'Content-Type' => 'application/json'},
161
+ :body => '{ "resources": [] }'
162
+ )
163
+ expect(subject).to eq({:resources => []})
164
+ end
165
+ end
166
+ end
167
+
168
+ describe '#change_password' do
169
+ let(:guid) { "foo-bar-baz" }
170
+ let(:old) { "old-pass" }
171
+ let(:new) { "new-pass" }
172
+
173
+ subject { uaa.change_password(guid, new, old) }
174
+
175
+ include_examples "UAA wrapper"
176
+
177
+ it 'sends a password change request' do
178
+ req = stub_request(:put, "#{target}/Users/#{guid}/password").with(
179
+ :headers => {
180
+ "Content-Type" => "application/json;charset=utf-8",
181
+ "Accept" => "application/json;charset=utf-8",
182
+ "Authorization" => auth_header
183
+ }
184
+ ).to_return(
185
+ :status => 200,
186
+ :headers => {'Content-Type' => 'application/json'},
187
+ :body => '{ "status": "ok", "message": "password_updated" }'
188
+ )
189
+
190
+ subject
191
+
192
+ expect(req).to have_been_requested
193
+ end
194
+ end
195
+
196
+ describe '#password_score' do
197
+ let(:password) { "password" }
198
+ let(:response) { MultiJson.encode({}) }
199
+
200
+ subject { uaa.password_score(password) }
201
+
202
+ include_examples "UAA wrapper"
203
+
204
+ before do
205
+ stub_request(:post, "#{target}/password/score").with(
206
+ :body => 'password=password',
207
+ :headers => {
208
+ 'Accept' => 'application/json;charset=utf-8',
209
+ 'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
210
+ }
211
+ ).to_return(
212
+ :status => 200,
213
+ :headers => {'Content-Type' => 'application/json'},
214
+ :body => response
215
+ )
216
+ end
217
+
218
+ context 'when the score is 0 and the required is 0' do
219
+ let(:response) { MultiJson.encode "score" => 0, "requiredScore" => 0 }
220
+ it { should == :good }
221
+ end
222
+
223
+ context 'when the score is less than the required score' do
224
+ let(:response) { MultiJson.encode "score" => 1, "requiredScore" => 5 }
225
+ it { should == :weak }
226
+ end
227
+
228
+ context 'and the score is equal to the required score' do
229
+ let(:response) { MultiJson.encode "score" => 5, "requiredScore" => 5 }
230
+ it { should == :good }
231
+ end
232
+
233
+ context 'and the score is greater than the required score' do
234
+ let(:response) { MultiJson.encode "score" => 6, "requiredScore" => 5 }
235
+ it { should == :good }
236
+ end
237
+
238
+ context 'and the score is 10' do
239
+ let(:response) { MultiJson.encode "score" => 10, "requiredScore" => 5 }
240
+ it { should == :strong }
241
+ end
242
+
243
+ context 'and the score is 10' do
244
+ let(:response) { MultiJson.encode "score" => 10, "requiredScore" => 10 }
245
+ it { should == :strong }
246
+ end
247
+
248
+ context 'and the score is invalid' do
249
+ let(:response) { MultiJson.encode "score" => 11, "requiredScore" => 5 }
250
+ it { should == :weak }
251
+ end
252
+ end
253
+
254
+ describe "#add_user" do
255
+ let(:email) { 'test@test.com' }
256
+ let(:password) { 'secret' }
257
+
258
+ context "without given/family name" do
259
+ subject { uaa.add_user(email, password) }
260
+
261
+ context 'with valid data' do
262
+ it "should add a user" do
263
+ req =
264
+ stub_request(:post, "https://uaa.example.com/Users").with(
265
+ :body =>
266
+ { :userName => email,
267
+ :emails => [{ :value => email }],
268
+ :password => password,
269
+ :name => { :givenName => email, :familyName => email }
270
+ }
271
+ ).to_return(
272
+ :status => 200,
273
+ :body => '{ "id" : "id" }',
274
+ :headers => { "Content-Type" => 'application/json' }
275
+ )
276
+
277
+ expect(subject).to eq({:id => "id"})
278
+ expect(req).to have_been_requested
279
+ end
280
+ end
281
+ end
282
+
283
+ context "with given/family name" do
284
+ let(:givenName) { 'givenName' }
285
+ let(:familyName) { 'familyName' }
286
+ subject { uaa.add_user(email, password, givenName: givenName, familyName: familyName) }
287
+
288
+ context 'with valid data' do
289
+ it "should add a user" do
290
+ req =
291
+ stub_request(:post, "https://uaa.example.com/Users").with(
292
+ :body =>
293
+ { :userName => email,
294
+ :emails => [{ :value => email }],
295
+ :password => password,
296
+ :name => { :givenName => givenName, :familyName => familyName }
297
+ }
298
+ ).to_return(
299
+ :status => 200,
300
+ :body => '{ "id" : "id" }',
301
+ :headers => { "Content-Type" => 'application/json' }
302
+ )
303
+
304
+ expect(subject).to eq({:id => "id"})
305
+ expect(req).to have_been_requested
306
+ end
307
+ end
308
+ end
309
+
310
+ end
311
+
312
+ describe "#delete_user" do
313
+ let(:guid) { "123" }
314
+ let!(:req) {
315
+ stub_request(
316
+ :delete,
317
+ "https://uaa.example.com/Users/123"
318
+ ).to_return(:status => 200, :body => '{ "foo": "bar" }')
319
+ }
320
+
321
+ subject { uaa }
322
+
323
+ it "wraps uaa errors" do
324
+ expect(uaa).to receive(:wrap_uaa_errors)
325
+ subject.delete_user(guid)
326
+ end
327
+
328
+ context 'with valid data' do
329
+ it "should add a user" do
330
+ subject.delete_user(guid)
331
+ expect(req).to have_been_requested
332
+ end
333
+ end
334
+ end
335
+
336
+ describe "#wrap_uaa_errors" do
337
+ subject { uaa.send(:wrap_uaa_errors) { raise error } }
338
+
339
+ context "when the block raises CF::UAA::BadResponse" do
340
+ let(:error) { CF::UAA::BadResponse }
341
+
342
+ it "raises CFoundry::BadResponse" do
343
+ expect { subject }.to raise_exception(CFoundry::BadResponse)
344
+ end
345
+ end
346
+
347
+ context "when the block raises CF::UAA::NotFound" do
348
+ let(:error) { CF::UAA::NotFound }
349
+
350
+ it "raises CFoundry::NotFound" do
351
+ expect { subject }.to raise_exception(CFoundry::NotFound)
352
+ end
353
+ end
354
+
355
+ context "when the block raises CF::UAA::InvalidToken" do
356
+ let(:error) { CF::UAA::InvalidToken }
357
+
358
+ it "raises CFoundry::Denied" do
359
+ expect { subject }.to raise_exception(CFoundry::Denied)
360
+ end
361
+ end
362
+
363
+ context "when the block raises CF::UAA::TargetError" do
364
+ let(:error) { CF::UAA::TargetError.new({ :error => "foo", :error_description => "bar" }) }
365
+
366
+ it "raises CFoundry::UAAError" do
367
+ expect { subject }.to raise_exception(CFoundry::UAAError, "foo: bar")
368
+ end
369
+ end
370
+ end
371
+
372
+ describe "#token_issuer" do
373
+ it "has logging level 0 if #trace is true" do
374
+ uaa.trace = true
375
+ expect(uaa.send(:token_issuer).logger.level).to eq -1
376
+ end
377
+
378
+ it "has logging level 1 if #trace is false" do
379
+ uaa.trace = false
380
+ expect(uaa.send(:token_issuer).logger.level).to eq 1
381
+ end
382
+
383
+ it "passes proxy info to the token issuer" do
384
+ allow(CF::UAA::TokenIssuer).to receive(:new).and_call_original
385
+ uaa.http_proxy = 'http-proxy.example.com'
386
+ uaa.https_proxy = 'https-proxy.example.com'
387
+
388
+ uaa.send(:token_issuer)
389
+
390
+ expect(CF::UAA::TokenIssuer).to have_received(:new).with(anything, anything, anything, hash_including(
391
+ http_proxy: 'http-proxy.example.com',
392
+ https_proxy: 'https-proxy.example.com'
393
+ ))
394
+ end
395
+ end
396
+
397
+ describe "#scim" do
398
+ it "has logging level 0 if #trace is true" do
399
+ uaa.trace = true
400
+ expect(uaa.send(:scim).logger.level).to eq -1
401
+ end
402
+
403
+ it "has logging level 1 if #trace is false" do
404
+ uaa.trace = false
405
+ expect(uaa.send(:scim).logger.level).to eq 1
406
+ end
407
+ end
408
+
409
+ describe "#try_to_refresh_token!" do
410
+ it "uses the refresh token to get a new access token" do
411
+ expect(uaa.send(:token_issuer)).to receive(:refresh_token_grant).with(uaa.token.refresh_token) do
412
+ CF::UAA::TokenInfo.new(
413
+ :token_type => "bearer",
414
+ :access_token => "refreshed-token",
415
+ :refresh_token => "some-refresh-token")
416
+ end
417
+
418
+ uaa.try_to_refresh_token!
419
+ expect(uaa.token.auth_header).to eq "bearer refreshed-token"
420
+ expect(uaa.token.refresh_token).to eq "some-refresh-token"
421
+ end
422
+
423
+ context "when the refresh token has expired" do
424
+ it "returns the current token" do
425
+ expect(uaa.send(:token_issuer)).to receive(:refresh_token_grant) do
426
+ raise CF::UAA::TargetError.new
427
+ end
428
+
429
+ expect {
430
+ uaa.try_to_refresh_token!
431
+ }.to_not change { uaa.token }
432
+ end
433
+ end
434
+ end
435
+ end
@@ -0,0 +1,182 @@
1
+ require "spec_helper"
2
+
3
+ class TestModelWithUploadHelpers < CFoundry::V2::Model
4
+ include CFoundry::UploadHelpers
5
+ end
6
+
7
+ module CFoundry
8
+ describe UploadHelpers do
9
+ describe "#upload" do
10
+ def relative_glob(dir)
11
+ base_pathname = Pathname.new(dir)
12
+ Dir["#{dir}/**/{*,.[^\.]*}"].map do |file|
13
+ Pathname.new(file).relative_path_from(base_pathname).to_s
14
+ end
15
+ end
16
+
17
+ def mock_zip(*args, &block)
18
+ if args.empty?
19
+ expect(CFoundry::Zip).to receive(:pack, &block)
20
+ else
21
+ expect(CFoundry::Zip).to receive(:pack).with(*args, &block)
22
+ end
23
+ end
24
+
25
+ let(:base) { Object.new }
26
+ let(:guid) { "123" }
27
+ let(:path) { "#{SPEC_ROOT}/fixtures/apps/with_cfignore" }
28
+ let(:check_resources) { false }
29
+ let(:tmpdir) { "#{SPEC_ROOT}/tmp/fake_tmpdir" }
30
+
31
+ let(:client) { build(:client) }
32
+
33
+ let(:model) { TestModelWithUploadHelpers.new(guid, client) }
34
+
35
+ before do
36
+ allow(client).to receive(:base) { base }
37
+ allow(base).to receive(:upload_app)
38
+
39
+ FileUtils.rm_rf tmpdir
40
+ allow(Dir).to receive(:tmpdir) do
41
+ FileUtils.mkdir_p tmpdir
42
+ tmpdir
43
+ end
44
+ end
45
+
46
+ it "zips the app and uploads the zip file" do
47
+ zip_path = "#{tmpdir}/#{guid}.zip"
48
+ mock_zip(anything, zip_path) { true }
49
+ allow(base).to receive(:upload_app).with(guid, zip_path, [])
50
+ model.upload(path, check_resources)
51
+ end
52
+
53
+ it "uploads an app with the right guid" do
54
+ mock_zip
55
+ expect(base).to receive(:upload_app).with(guid, anything, anything)
56
+ model.upload(path, check_resources)
57
+ end
58
+
59
+ it "uses a unique directory name when it copies the app" do
60
+ mock_zip(/#{tmpdir}.*#{guid}.*/, anything)
61
+ model.upload(path, check_resources)
62
+ end
63
+
64
+ it "cleans up after itself correctly" do
65
+ model.upload(path, check_resources)
66
+ expect(relative_glob(tmpdir)).to be_empty
67
+ end
68
+
69
+ it "includes the source files of the app in the zip file" do
70
+ mock_zip do |src, _|
71
+ files = relative_glob(src)
72
+ expect(files).to include "non_ignored_dir"
73
+ expect(files).to include "non_ignored_file.txt"
74
+ expect(files).to include "non_ignored_dir/file_in_non_ignored_dir.txt"
75
+ end
76
+ model.upload(path, check_resources)
77
+ end
78
+
79
+ it "includes hidden files (though stager ignores them currently)" do
80
+ mock_zip do |src, _|
81
+ expect(relative_glob(src)).to include ".hidden_file"
82
+ end
83
+ model.upload(path, check_resources)
84
+ end
85
+
86
+ it "does not include files and directories specified in the cfignore" do
87
+ mock_zip do |src, _|
88
+ files = relative_glob(src)
89
+ expect(files).to match_array(%w[
90
+ .hidden_file .cfignore non_ignored_dir ambiguous_ignored
91
+ non_ignored_dir/file_in_non_ignored_dir.txt non_ignored_file.txt
92
+ non_ignored_dir/toplevel_ignored.txt
93
+ ])
94
+ end
95
+ model.upload(path, check_resources)
96
+ end
97
+
98
+ %w(.git _darcs .svn).each do |source_control_dir_name|
99
+ context "when there is a #{source_control_dir_name} directory in the app" do
100
+ before { FileUtils.mkdir_p("#{path}/#{source_control_dir_name}") }
101
+
102
+ it "ignores that directory" do
103
+ mock_zip do |src, _|
104
+ expect(relative_glob(src)).not_to include source_control_dir_name
105
+ end
106
+ model.upload(path, check_resources)
107
+ end
108
+ end
109
+ end
110
+
111
+ context "when there are no files to zip" do
112
+ before { mock_zip { false } }
113
+
114
+ it "passes `false` to #upload_app" do
115
+ expect(base).to receive(:upload_app).with(guid, false, [])
116
+ model.upload(path, check_resources)
117
+ end
118
+ end
119
+
120
+ context "when all files match existing resources" do
121
+ context "and there are directories" do
122
+ let(:path) { "#{SPEC_ROOT}/fixtures/apps/with_nested_directories" }
123
+
124
+ it "prunes them before zipping" do
125
+ allow(model).to receive(:make_fingerprints).with(anything) do
126
+ [[], CFoundry::UploadHelpers::RESOURCE_CHECK_LIMIT + 1]
127
+ end
128
+
129
+ allow(base).to receive(:resource_match).with(anything) do
130
+ %w{ xyz foo/bar/baz/fizz }.map do |path|
131
+ {:fn => "#{tmpdir}/.cf_#{guid}_files/#{path}"}
132
+ end
133
+ end
134
+
135
+ expect(base).to receive(:upload_app).with(anything, false, anything)
136
+ model.upload(path)
137
+ end
138
+ end
139
+ end
140
+
141
+ context "when only dotfiles don't match existing resources" do
142
+ let(:path) { "#{SPEC_ROOT}/fixtures/apps/with_dotfiles" }
143
+
144
+ it "does not prune them" do
145
+ allow(model).to receive(:make_fingerprints).with(anything) do
146
+ [[], CFoundry::UploadHelpers::RESOURCE_CHECK_LIMIT + 1]
147
+ end
148
+
149
+ allow(base).to receive(:resource_match).with(anything) do
150
+ %w{ xyz }.map do |path|
151
+ {:fn => "#{tmpdir}/.cf_#{guid}_files/#{path}"}
152
+ end
153
+ end
154
+
155
+ expect(base).to receive(:upload_app).with(anything, anything, anything) do |_, zip, _|
156
+ expect(zip).to be_a(String)
157
+ end
158
+
159
+ model.upload(path)
160
+ end
161
+ end
162
+
163
+ context "when there is a symlink pointing outside of the root" do
164
+ let(:path) { "#{SPEC_ROOT}/fixtures/apps/with_external_symlink" }
165
+
166
+ it "blows up" do
167
+ expect {
168
+ model.upload(path)
169
+ }.to raise_error(CFoundry::Error, /contains links.*that point outside/)
170
+ end
171
+
172
+ context "and it is cfignored" do
173
+ let(:path) { "#{SPEC_ROOT}/fixtures/apps/with_ignored_external_symlink" }
174
+
175
+ it "ignores it" do
176
+ expect { model.upload(path) }.to_not raise_error
177
+ end
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end