ncfoundry 4.9.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 (268) 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 +41 -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 +62 -0
  36. data/lib/cfoundry/baseclient.rb +220 -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 +14 -0
  41. data/lib/cfoundry/errors.rb +163 -0
  42. data/lib/cfoundry/rest_client.rb +316 -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 +151 -0
  46. data/lib/cfoundry/upload_helpers.rb +222 -0
  47. data/lib/cfoundry/v2/app.rb +313 -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 +112 -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 +13 -0
  57. data/lib/cfoundry/v2/model.rb +213 -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 +145 -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 +31 -0
  77. data/lib/cfoundry/v2/stack.rb +10 -0
  78. data/lib/cfoundry/v2/user.rb +97 -0
  79. data/lib/cfoundry/v2/user_provided_service_instance.rb +16 -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 +6 -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 +153 -0
  157. data/spec/cfoundry/baseclient_spec.rb +284 -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 +367 -0
  161. data/spec/cfoundry/trace_helpers_spec.rb +91 -0
  162. data/spec/cfoundry/uaaclient_spec.rb +421 -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 +472 -0
  179. data/spec/cfoundry/v2/organization_spec.rb +282 -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 +160 -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/v1.yml +189 -0
  267. data/vendor/errors/v2.yml +845 -0
  268. metadata +712 -0
@@ -0,0 +1,421 @@
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 '#prompts' do
29
+ subject { uaa.prompts }
30
+
31
+ include_examples "UAA wrapper"
32
+
33
+ # GET (target)/login
34
+ it "receives the prompts from /login" do
35
+ stub_request(:get, "#{target}/login").to_return :status => 200,
36
+ :headers => {'Content-Type' => 'application/json'},
37
+ :body => <<EOF
38
+ {
39
+ "timestamp": "2012-11-08T13:32:18+0000",
40
+ "commit_id": "ebbf817",
41
+ "app": {
42
+ "version": "1.2.6",
43
+ "artifact": "cloudfoundry-identity-uaa",
44
+ "description": "User Account and Authentication Service",
45
+ "name": "UAA"
46
+ },
47
+ "prompts": {
48
+ "username": [
49
+ "text",
50
+ "Email"
51
+ ],
52
+ "password": [
53
+ "password",
54
+ "Password"
55
+ ]
56
+ }
57
+ }
58
+ EOF
59
+
60
+ expect(subject).to eq(
61
+ :username => ["text", "Email"],
62
+ :password => ["password", "Password"])
63
+ end
64
+ end
65
+
66
+ describe '#authorize' do
67
+ let(:username) { "foo@bar.com" }
68
+ let(:password) { "test" }
69
+ let(:creds) { {:username => username, :password => password} }
70
+ let(:state) { 'somestate' }
71
+ let(:redirect_uri) { 'https://uaa.example.com/redirect/cf' }
72
+ let(:auth) { Object.new }
73
+ let(:issuer) { Object.new }
74
+
75
+ subject { uaa.authorize(creds) }
76
+
77
+ before do
78
+ allow(issuer).to receive(:request_token) { auth }
79
+ allow(uaa).to receive(:token_issuer) { issuer }
80
+ end
81
+
82
+ include_examples "UAA wrapper"
83
+
84
+ it 'returns the token on successful authentication' do
85
+ expect(issuer)
86
+ .to receive(:request_token)
87
+ .with(:grant_type => "password",
88
+ :scope => nil,
89
+ :username => username,
90
+ :password => password) { auth }
91
+ expect(subject).to eq auth
92
+ end
93
+
94
+ context 'when authorization fails' do
95
+ context 'in the expected way' do
96
+ it 'raises a CFoundry::Denied error' do
97
+ expect(issuer).to receive(:request_token) { raise CF::UAA::BadResponse.new("401: FooBar") }
98
+ expect { subject }.to raise_error(CFoundry::Denied, "401: Authorization failed")
99
+ end
100
+ end
101
+
102
+
103
+ context 'in an unexpected way' do
104
+ it 'raises a CFoundry::Denied error' do
105
+ expect(issuer).to receive(:request_token) { raise CF::UAA::BadResponse.new("no_status_code") }
106
+ expect { subject }.to raise_error(CFoundry::Denied, "400: Authorization failed")
107
+ end
108
+ end
109
+
110
+ context "with a CF::UAA::TargetError" do
111
+ before { allow(issuer).to receive(:request_token) { raise CF::UAA::TargetError.new("useless info") } }
112
+
113
+ it "retries with implicit grant" do
114
+ expect(issuer).to receive(:implicit_grant_with_creds).with(:username => username, :password => password)
115
+ expect { subject }.to_not raise_error
116
+ end
117
+
118
+ it "fails with Denied when given a 401" do
119
+ allow(issuer).to receive(:implicit_grant_with_creds) { raise CF::UAA::BadResponse.new("status 401") }
120
+ expect { subject }.to raise_error(CFoundry::Denied, "401: Authorization failed")
121
+ end
122
+
123
+ it "fails with Denied when given any other status code" do
124
+ allow(issuer).to receive(:implicit_grant_with_creds) { raise CF::UAA::BadResponse.new("no status code") }
125
+ expect { subject }.to raise_error(CFoundry::Denied, "400: Authorization failed")
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#users' do
132
+ subject { uaa.users }
133
+
134
+ it 'requests /Users' do
135
+ stub_request(:get, "#{target}/Users").with(
136
+ :headers => { "authorization" => auth_header }
137
+ ).to_return(
138
+ :headers => {'Content-Type' => 'application/json'},
139
+ :body => '{ "resources": [] }'
140
+ )
141
+ expect(subject).to eq({:resources => []})
142
+ end
143
+
144
+ context "when there is no token" do
145
+ before { uaa.token = nil }
146
+
147
+ it "doesn't blow up" do
148
+ stub_request(:get, "#{target}/Users").to_return(
149
+ :headers => {'Content-Type' => 'application/json'},
150
+ :body => '{ "resources": [] }'
151
+ )
152
+ expect(subject).to eq({:resources => []})
153
+ end
154
+ end
155
+ end
156
+
157
+ describe '#change_password' do
158
+ let(:guid) { "foo-bar-baz" }
159
+ let(:old) { "old-pass" }
160
+ let(:new) { "new-pass" }
161
+
162
+ subject { uaa.change_password(guid, new, old) }
163
+
164
+ include_examples "UAA wrapper"
165
+
166
+ it 'sends a password change request' do
167
+ req = stub_request(:put, "#{target}/Users/#{guid}/password").with(
168
+ :headers => {
169
+ "Content-Type" => "application/json;charset=utf-8",
170
+ "Accept" => "application/json;charset=utf-8",
171
+ "Authorization" => auth_header
172
+ }
173
+ ).to_return(
174
+ :status => 200,
175
+ :headers => {'Content-Type' => 'application/json'},
176
+ :body => '{ "status": "ok", "message": "password_updated" }'
177
+ )
178
+
179
+ subject
180
+
181
+ expect(req).to have_been_requested
182
+ end
183
+ end
184
+
185
+ describe '#password_score' do
186
+ let(:password) { "password" }
187
+ let(:response) { MultiJson.encode({}) }
188
+
189
+ subject { uaa.password_score(password) }
190
+
191
+ include_examples "UAA wrapper"
192
+
193
+ before do
194
+ stub_request(:post, "#{target}/password/score").with(
195
+ :body => 'password=password',
196
+ :headers => {
197
+ 'Accept' => 'application/json;charset=utf-8',
198
+ 'Content-Type' => 'application/x-www-form-urlencoded;charset=utf-8',
199
+ }
200
+ ).to_return(
201
+ :status => 200,
202
+ :headers => {'Content-Type' => 'application/json'},
203
+ :body => response
204
+ )
205
+ end
206
+
207
+ context 'when the score is 0 and the required is 0' do
208
+ let(:response) { MultiJson.encode "score" => 0, "requiredScore" => 0 }
209
+ it { should == :good }
210
+ end
211
+
212
+ context 'when the score is less than the required score' do
213
+ let(:response) { MultiJson.encode "score" => 1, "requiredScore" => 5 }
214
+ it { should == :weak }
215
+ end
216
+
217
+ context 'and the score is equal to the required score' do
218
+ let(:response) { MultiJson.encode "score" => 5, "requiredScore" => 5 }
219
+ it { should == :good }
220
+ end
221
+
222
+ context 'and the score is greater than the required score' do
223
+ let(:response) { MultiJson.encode "score" => 6, "requiredScore" => 5 }
224
+ it { should == :good }
225
+ end
226
+
227
+ context 'and the score is 10' do
228
+ let(:response) { MultiJson.encode "score" => 10, "requiredScore" => 5 }
229
+ it { should == :strong }
230
+ end
231
+
232
+ context 'and the score is 10' do
233
+ let(:response) { MultiJson.encode "score" => 10, "requiredScore" => 10 }
234
+ it { should == :strong }
235
+ end
236
+
237
+ context 'and the score is invalid' do
238
+ let(:response) { MultiJson.encode "score" => 11, "requiredScore" => 5 }
239
+ it { should == :weak }
240
+ end
241
+ end
242
+
243
+ describe "#add_user" do
244
+ let(:email) { 'test@test.com' }
245
+ let(:password) { 'secret' }
246
+
247
+ context "without given/family name" do
248
+ subject { uaa.add_user(email, password) }
249
+
250
+ context 'with valid data' do
251
+ it "should add a user" do
252
+ req =
253
+ stub_request(:post, "https://uaa.example.com/Users").with(
254
+ :body =>
255
+ { :userName => email,
256
+ :emails => [{ :value => email }],
257
+ :password => password,
258
+ :name => { :givenName => email, :familyName => email }
259
+ }
260
+ ).to_return(
261
+ :status => 200,
262
+ :body => '{ "id" : "id" }',
263
+ :headers => { "Content-Type" => 'application/json' }
264
+ )
265
+
266
+ expect(subject).to eq({:id => "id"})
267
+ expect(req).to have_been_requested
268
+ end
269
+ end
270
+ end
271
+
272
+ context "with given/family name" do
273
+ let(:givenName) { 'givenName' }
274
+ let(:familyName) { 'familyName' }
275
+ subject { uaa.add_user(email, password, givenName: givenName, familyName: familyName) }
276
+
277
+ context 'with valid data' do
278
+ it "should add a user" do
279
+ req =
280
+ stub_request(:post, "https://uaa.example.com/Users").with(
281
+ :body =>
282
+ { :userName => email,
283
+ :emails => [{ :value => email }],
284
+ :password => password,
285
+ :name => { :givenName => givenName, :familyName => familyName }
286
+ }
287
+ ).to_return(
288
+ :status => 200,
289
+ :body => '{ "id" : "id" }',
290
+ :headers => { "Content-Type" => 'application/json' }
291
+ )
292
+
293
+ expect(subject).to eq({:id => "id"})
294
+ expect(req).to have_been_requested
295
+ end
296
+ end
297
+ end
298
+
299
+ end
300
+
301
+ describe "#delete_user" do
302
+ let(:guid) { "123" }
303
+ let!(:req) {
304
+ stub_request(
305
+ :delete,
306
+ "https://uaa.example.com/Users/123"
307
+ ).to_return(:status => 200, :body => '{ "foo": "bar" }')
308
+ }
309
+
310
+ subject { uaa }
311
+
312
+ it "wraps uaa errors" do
313
+ expect(uaa).to receive(:wrap_uaa_errors)
314
+ subject.delete_user(guid)
315
+ end
316
+
317
+ context 'with valid data' do
318
+ it "should add a user" do
319
+ subject.delete_user(guid)
320
+ expect(req).to have_been_requested
321
+ end
322
+ end
323
+ end
324
+
325
+ describe "#wrap_uaa_errors" do
326
+ subject { uaa.send(:wrap_uaa_errors) { raise error } }
327
+
328
+ context "when the block raises CF::UAA::BadResponse" do
329
+ let(:error) { CF::UAA::BadResponse }
330
+
331
+ it "raises CFoundry::BadResponse" do
332
+ expect { subject }.to raise_exception(CFoundry::BadResponse)
333
+ end
334
+ end
335
+
336
+ context "when the block raises CF::UAA::NotFound" do
337
+ let(:error) { CF::UAA::NotFound }
338
+
339
+ it "raises CFoundry::NotFound" do
340
+ expect { subject }.to raise_exception(CFoundry::NotFound)
341
+ end
342
+ end
343
+
344
+ context "when the block raises CF::UAA::InvalidToken" do
345
+ let(:error) { CF::UAA::InvalidToken }
346
+
347
+ it "raises CFoundry::Denied" do
348
+ expect { subject }.to raise_exception(CFoundry::Denied)
349
+ end
350
+ end
351
+
352
+ context "when the block raises CF::UAA::TargetError" do
353
+ let(:error) { CF::UAA::TargetError.new({ :error => "foo", :error_description => "bar" }) }
354
+
355
+ it "raises CFoundry::UAAError" do
356
+ expect { subject }.to raise_exception(CFoundry::UAAError, "foo: bar")
357
+ end
358
+ end
359
+ end
360
+
361
+ describe "#token_issuer" do
362
+ it "has logging level 0 if #trace is true" do
363
+ uaa.trace = true
364
+ expect(uaa.send(:token_issuer).logger.level).to eq -1
365
+ end
366
+
367
+ it "has logging level 1 if #trace is false" do
368
+ uaa.trace = false
369
+ expect(uaa.send(:token_issuer).logger.level).to eq 1
370
+ end
371
+
372
+ it "passes proxy info to the token issuer" do
373
+ allow(CF::UAA::TokenIssuer).to receive(:new).and_call_original
374
+
375
+ uaa.send(:token_issuer)
376
+
377
+ expect(CF::UAA::TokenIssuer).to have_received(:new).with(anything, anything, anything, hash_including(
378
+ symbolize_keys: true
379
+ ))
380
+ end
381
+ end
382
+
383
+ describe "#scim" do
384
+ it "has logging level 0 if #trace is true" do
385
+ uaa.trace = true
386
+ expect(uaa.send(:scim).logger.level).to eq -1
387
+ end
388
+
389
+ it "has logging level 1 if #trace is false" do
390
+ uaa.trace = false
391
+ expect(uaa.send(:scim).logger.level).to eq 1
392
+ end
393
+ end
394
+
395
+ describe "#try_to_refresh_token!" do
396
+ it "uses the refresh token to get a new access token" do
397
+ expect(uaa.send(:token_issuer)).to receive(:refresh_token_grant).with(uaa.token.refresh_token) do
398
+ CF::UAA::TokenInfo.new(
399
+ :token_type => "bearer",
400
+ :access_token => "refreshed-token",
401
+ :refresh_token => "some-refresh-token")
402
+ end
403
+
404
+ uaa.try_to_refresh_token!
405
+ expect(uaa.token.auth_header).to eq "bearer refreshed-token"
406
+ expect(uaa.token.refresh_token).to eq "some-refresh-token"
407
+ end
408
+
409
+ context "when the refresh token has expired" do
410
+ it "returns the current token" do
411
+ expect(uaa.send(:token_issuer)).to receive(:refresh_token_grant) do
412
+ raise CF::UAA::TargetError.new
413
+ end
414
+
415
+ expect {
416
+ uaa.try_to_refresh_token!
417
+ }.to_not change { uaa.token }
418
+ end
419
+ end
420
+ end
421
+ 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
@@ -0,0 +1,97 @@
1
+ require "spec_helper"
2
+
3
+ module CFoundry
4
+ module V2
5
+ describe AppEvent do
6
+ let(:app) { build(:app) }
7
+ let(:app_event) { build(:app_event, :app => app) }
8
+
9
+ it "has an app" do
10
+ expect(app_event.app).to eq(app)
11
+ end
12
+
13
+ describe "#instance_guid" do
14
+ it "has an instance guid" do
15
+ app_event.instance_guid = "foo"
16
+ expect(app_event.instance_guid).to eq("foo")
17
+ end
18
+
19
+ context "when an invalid value is assigned" do
20
+ it "raises a Mismatch exception" do
21
+ expect {
22
+ app_event.instance_guid = 123
23
+ }.to raise_error(Mismatch)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe "#instance_index" do
29
+ it "has an instance index" do
30
+ app_event.instance_index = 123
31
+ expect(app_event.instance_index).to eq(123)
32
+ end
33
+
34
+ context "when an invalid value is assigned" do
35
+ it "raises a Mismatch exception" do
36
+ expect {
37
+ app_event.instance_index = "wrong"
38
+ }.to raise_error(Mismatch)
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#exit_status" do
44
+ it "has an instance index" do
45
+ app_event.exit_status = 123
46
+ expect(app_event.exit_status).to eq(123)
47
+ end
48
+
49
+ context "when an invalid value is assigned" do
50
+ it "raises a Mismatch exception" do
51
+ expect {
52
+ app_event.exit_status = "wrong"
53
+ }.to raise_error(Mismatch)
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#exit_description" do
59
+ before do
60
+ stub_request(:get, /v2\/app_events\/.*/).to_return(:body => {:entity => {}}.to_json)
61
+ end
62
+
63
+ it "defaults to an empty string" do
64
+ expect(app_event.exit_description).to eq("")
65
+ end
66
+
67
+ it "has an instance guid" do
68
+ app_event.exit_description = "foo"
69
+ expect(app_event.exit_description).to eq("foo")
70
+ end
71
+
72
+ context "when an invalid value is assigned" do
73
+ it "raises a Mismatch exception" do
74
+ expect {
75
+ app_event.exit_description = 123
76
+ }.to raise_error(Mismatch)
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#timestamp" do
82
+ it "has a timestamp" do
83
+ app_event.timestamp = "2013-04-23 12:43:23 +0000"
84
+ expect(app_event.timestamp).to eq("2013-04-23 12:43:23 +0000")
85
+ end
86
+
87
+ context "when an invalid value is assigned" do
88
+ it "raises a Mismatch exception" do
89
+ expect {
90
+ app_event.timestamp = 42
91
+ }.to raise_error(Mismatch)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end