scalingo 3.4.0 → 3.6.0

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependabot.yml +17 -0
  3. data/.github/workflows/publish.yml +1 -1
  4. data/.github/workflows/ruby.yml +3 -3
  5. data/.rubocop.yml +9 -21
  6. data/CHANGELOG.md +10 -0
  7. data/lib/scalingo/api/client.rb +6 -15
  8. data/lib/scalingo/api/response.rb +3 -3
  9. data/lib/scalingo/auth/tokens.rb +2 -2
  10. data/lib/scalingo/auth.rb +1 -1
  11. data/lib/scalingo/billing.rb +1 -1
  12. data/lib/scalingo/client.rb +6 -6
  13. data/lib/scalingo/configuration.rb +3 -3
  14. data/lib/scalingo/core_client.rb +2 -3
  15. data/lib/scalingo/regional/addons.rb +1 -1
  16. data/lib/scalingo/regional.rb +1 -1
  17. data/lib/scalingo/regional_database.rb +1 -1
  18. data/lib/scalingo/token_holder.rb +1 -1
  19. data/lib/scalingo/version.rb +1 -1
  20. data/scalingo.gemspec +5 -8
  21. metadata +13 -97
  22. data/spec/scalingo/api/client_spec.rb +0 -256
  23. data/spec/scalingo/api/endpoint_spec.rb +0 -45
  24. data/spec/scalingo/api/response_spec.rb +0 -301
  25. data/spec/scalingo/auth/keys_spec.rb +0 -58
  26. data/spec/scalingo/auth/scm_integrations_spec.rb +0 -58
  27. data/spec/scalingo/auth/tokens_spec.rb +0 -74
  28. data/spec/scalingo/auth/two_factor_auth_spec.rb +0 -69
  29. data/spec/scalingo/auth/user_spec.rb +0 -31
  30. data/spec/scalingo/auth_spec.rb +0 -15
  31. data/spec/scalingo/bearer_token_spec.rb +0 -72
  32. data/spec/scalingo/billing/profile_spec.rb +0 -55
  33. data/spec/scalingo/billing_spec.rb +0 -11
  34. data/spec/scalingo/client_spec.rb +0 -93
  35. data/spec/scalingo/configuration_spec.rb +0 -57
  36. data/spec/scalingo/core_client_spec.rb +0 -23
  37. data/spec/scalingo/regional/addons_spec.rb +0 -169
  38. data/spec/scalingo/regional/apps_spec.rb +0 -137
  39. data/spec/scalingo/regional/autoscalers_spec.rb +0 -84
  40. data/spec/scalingo/regional/collaborators_spec.rb +0 -69
  41. data/spec/scalingo/regional/containers_spec.rb +0 -67
  42. data/spec/scalingo/regional/deployments_spec.rb +0 -45
  43. data/spec/scalingo/regional/domains_spec.rb +0 -84
  44. data/spec/scalingo/regional/environment_spec.rb +0 -77
  45. data/spec/scalingo/regional/events_spec.rb +0 -65
  46. data/spec/scalingo/regional/logs_spec.rb +0 -39
  47. data/spec/scalingo/regional/metrics_spec.rb +0 -46
  48. data/spec/scalingo/regional/notifiers_spec.rb +0 -113
  49. data/spec/scalingo/regional/operations_spec.rb +0 -27
  50. data/spec/scalingo/regional/scm_repo_links_spec.rb +0 -48
  51. data/spec/scalingo/regional_database/backups_spec.rb +0 -58
  52. data/spec/scalingo/regional_database/databases_spec.rb +0 -39
  53. data/spec/scalingo/regional_database_spec.rb +0 -11
  54. data/spec/scalingo/regional_spec.rb +0 -14
  55. data/spec/scalingo/token_holder_spec.rb +0 -81
@@ -1,256 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe Scalingo::API::Client do
4
- let(:url) { "http://localhost" }
5
-
6
- subject { described_class.new(url, scalingo: scalingo) }
7
-
8
- describe "initialize" do
9
- let(:config) { {default_region: :test} }
10
-
11
- describe "with only url" do
12
- subject { described_class.new(:url) }
13
-
14
- it "stores the url" do
15
- expect(subject.url).to eq(:url)
16
- end
17
-
18
- it "uses itself as token holder" do
19
- expect(subject.token_holder).to eq(subject)
20
- end
21
-
22
- it "configuration is the global one" do
23
- expect(Scalingo::Configuration).to receive(:new).with({}, Scalingo.config).and_return(:config).once
24
-
25
- expect(subject.config).to eq(:config)
26
- end
27
- end
28
-
29
- describe "with scalingo client supplied" do
30
- subject { described_class.new(:url, scalingo: scalingo) }
31
-
32
- it "uses the scalingo client as token holder" do
33
- expect(subject.token_holder).to eq(scalingo)
34
- end
35
-
36
- it "configuration is herited from the scalingo client" do
37
- expect(Scalingo::Configuration).to receive(:new).with({}, scalingo.config).once
38
-
39
- subject
40
- end
41
- end
42
-
43
- describe "with config supplied" do
44
- subject { described_class.new(:url, config: config) }
45
-
46
- it "configuration is herited from the global one" do
47
- expect(Scalingo::Configuration).to receive(:new).with(config, Scalingo.config).and_return(:config).once
48
-
49
- expect(subject.config).to eq(:config)
50
- end
51
- end
52
-
53
- describe "with both supplied" do
54
- subject { described_class.new(:url, scalingo: scalingo, config: config) }
55
-
56
- it "configuration is herited from the scalingo one" do
57
- expect(Scalingo::Configuration).to receive(:new).with(config, scalingo.config).once
58
-
59
- subject
60
- end
61
- end
62
- end
63
-
64
- describe "self.register_handler(s)!" do
65
- it "is called for each key/value pair" do
66
- expect(described_class).to receive(:register_handler!).with(:a, :b).once
67
- expect(described_class).to receive(:register_handler!).with(:c, :d).once
68
-
69
- described_class.register_handlers!(a: :b, c: :d)
70
- end
71
-
72
- it "defines a lazy-loaded memoized getter, returning an instance of the class supplied" do
73
- mock = double
74
-
75
- described_class.register_handler!(:handler, mock)
76
- instance = described_class.new(:url, scalingo: scalingo)
77
-
78
- # Only 1 instanciation should be done, no matter how many calls are done below
79
- expect(mock).to receive(:new).with(instance).and_return("1st").once
80
-
81
- # Not yet loaded...
82
- expect(instance.instance_variable_get(:@handler)).to eq(nil)
83
- instance.handler
84
-
85
- # Memoized...
86
- expect(instance.instance_variable_get(:@handler)).not_to eq(nil)
87
-
88
- # More calls won't try to perform more instanciations
89
- instance.handler
90
- instance.handler
91
- end
92
- end
93
-
94
- describe "headers" do
95
- before do
96
- expect(scalingo.config).to receive(:user_agent).and_return(user_agent).once
97
- end
98
-
99
- let(:user_agent) { "user agent" }
100
- let(:extra_hash) { {"X-Other" => "other"} }
101
- let(:extra_block) {
102
- proc { {"X-Another" => "another"} }
103
- }
104
-
105
- it "only returns the user agent and accept if nothing else is configured" do
106
- expect(subject.headers).to eq("Accept" => "application/json", "User-Agent" => user_agent)
107
- end
108
-
109
- it "allows additional headers to be globally configured" do
110
- expect(scalingo.config).to receive(:additional_headers).and_return(extra_hash)
111
-
112
- expect(subject.headers).to eq("Accept" => "application/json", "User-Agent" => user_agent, "X-Other" => "other")
113
- end
114
-
115
- it "additional headers can be a block" do
116
- expect(scalingo.config).to receive(:additional_headers).and_return(extra_block)
117
-
118
- expect(subject.headers).to eq("Accept" => "application/json", "User-Agent" => user_agent, "X-Another" => "another")
119
- end
120
- end
121
-
122
- describe "connection_options" do
123
- it "returns the url and headers" do
124
- expect(subject).to receive(:url).and_return("url").once
125
- expect(subject).to receive(:headers).and_return("headers").once
126
-
127
- expect(subject.connection_options).to eq(url: "url", headers: "headers")
128
- end
129
- end
130
-
131
- describe "unauthenticated_connection" do
132
- it "returns a memoized object" do
133
- expect(Faraday).to receive(:new).with(subject.connection_options).and_return("faraday").once
134
-
135
- expect(subject.unauthenticated_connection).to eq "faraday"
136
-
137
- subject.unauthenticated_connection
138
- subject.unauthenticated_connection
139
- end
140
-
141
- it "has no authentication header set" do
142
- expect(subject.unauthenticated_connection.headers.key?("Authorization")).not_to be true
143
- end
144
- end
145
-
146
- describe "authenticated_connection" do
147
- context "without bearer token" do
148
- let(:scalingo) { scalingo_guest }
149
-
150
- it "raises if configured to" do
151
- expect(scalingo.config).to receive(:raise_on_missing_authentication).and_return(true).once
152
-
153
- expect {
154
- subject.authenticated_connection
155
- }.to raise_error(Scalingo::Error::Unauthenticated)
156
- end
157
-
158
- it "returns an unauthenticated connection if configured to not raise" do
159
- expect(scalingo.config).to receive(:raise_on_missing_authentication).and_return(false).once
160
-
161
- expect(subject).to receive(:unauthenticated_connection).and_return(:object).once
162
- expect(subject.authenticated_connection).to eq(:object)
163
- end
164
- end
165
-
166
- context "with bearer token" do
167
- it "has an authentication header set with a bearer scheme" do
168
- expect(subject.connection.headers["Authorization"]).to eq "Bearer #{subject.token_holder.token.value}"
169
- end
170
- end
171
- end
172
-
173
- describe "database_connection" do
174
- let(:database_id) { "db-id-1234" }
175
-
176
- context "without bearer token" do
177
- let(:scalingo) { scalingo_guest }
178
-
179
- it "raises" do
180
- expect {
181
- subject.database_connection(database_id)
182
- }.to raise_error(Scalingo::Error::Unauthenticated)
183
- end
184
- end
185
-
186
- context "with bearer token" do
187
- it "has an authentication header set with a bearer scheme" do
188
- scalingo.authenticate_database_with_bearer_token(
189
- database_id,
190
- "1234",
191
- expires_at: Time.now + 1.hour,
192
- raise_on_expired_token: false,
193
- )
194
- expect(subject.database_connection(database_id).headers["Authorization"]).to eq "Bearer #{subject.token_holder.database_tokens[database_id].value}"
195
- end
196
- end
197
-
198
- context "with wrong bearer token" do
199
- it "raises" do
200
- database_id_2 = "db-id-5678"
201
- scalingo.authenticate_database_with_bearer_token(
202
- database_id_2,
203
- "1234",
204
- expires_at: Time.now + 1.hour,
205
- raise_on_expired_token: false,
206
- )
207
- expect {
208
- subject.database_connection(database_id)
209
- }.to raise_error(Scalingo::Error::Unauthenticated)
210
- end
211
- end
212
- end
213
-
214
- describe "connection" do
215
- context "logged" do
216
- context "no fallback to guest" do
217
- it "calls and return the authenticated_connection" do
218
- expect(subject).to receive(:authenticated_connection).and_return(:conn)
219
- expect(subject.connection).to eq(:conn)
220
- end
221
- end
222
-
223
- context "with fallback to guest" do
224
- it "calls and return the authenticated_connection" do
225
- expect(subject).to receive(:authenticated_connection).and_return(:conn)
226
- expect(subject.connection(fallback_to_guest: true)).to eq(:conn)
227
- end
228
- end
229
- end
230
-
231
- context "not logged" do
232
- let(:scalingo) { scalingo_guest }
233
-
234
- context "no fallback to guest" do
235
- it "raises when set to raise" do
236
- expect(scalingo.config).to receive(:raise_on_missing_authentication).and_return(true).once
237
-
238
- expect { subject.connection }.to raise_error(Scalingo::Error::Unauthenticated)
239
- end
240
-
241
- it "calls and return the unauthenticated_connection when set not to raise" do
242
- expect(scalingo.config).to receive(:raise_on_missing_authentication).and_return(false).once
243
- expect(subject).to receive(:unauthenticated_connection).and_return(:conn)
244
- expect(subject.connection(fallback_to_guest: true)).to eq(:conn)
245
- end
246
- end
247
-
248
- context "with fallback to guest" do
249
- it "calls and return the unauthenticated_connection" do
250
- expect(subject).to receive(:unauthenticated_connection).and_return(:conn)
251
- expect(subject.connection(fallback_to_guest: true)).to eq(:conn)
252
- end
253
- end
254
- end
255
- end
256
- end
@@ -1,45 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe Scalingo::API::Endpoint do
4
- let(:client) { double }
5
-
6
- subject { described_class.new(client) }
7
-
8
- describe "initialize" do
9
- it "stores the client" do
10
- instance = described_class.new(:client)
11
-
12
- expect(instance.client).to eq(:client)
13
- end
14
- end
15
-
16
- describe "connection" do
17
- it "delegates the connection to the client" do
18
- expect(client).to receive(:connection).and_return(:value).once
19
- expect(subject.connection).to eq :value
20
- end
21
- end
22
-
23
- describe "unpack" do
24
- it "forwards unpack to Response without keys" do
25
- mock = proc { 1 }
26
-
27
- expect(Scalingo::API::Response).to receive(:unpack).with(client, keys: [], &mock).and_return(:d).once
28
- expect(subject.send(:unpack, &mock)).to eq :d
29
- end
30
-
31
- it "forwards unpack to Response with a single key" do
32
- mock = proc { 1 }
33
-
34
- expect(Scalingo::API::Response).to receive(:unpack).with(client, keys: [:a], &mock).and_return(:d).once
35
- expect(subject.send(:unpack, :a, &mock)).to eq :d
36
- end
37
-
38
- it "forwards unpack to Response with many keys" do
39
- mock = proc { 1 }
40
-
41
- expect(Scalingo::API::Response).to receive(:unpack).with(client, keys: [:a, :b], &mock).and_return(:d).once
42
- expect(subject.send(:unpack, :a, :b, &mock)).to eq :d
43
- end
44
- end
45
- end
@@ -1,301 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe Scalingo::API::Response do
4
- let(:client) { regional }
5
- let(:status) { 200 }
6
- let(:headers) { {} }
7
- let(:data) { "" }
8
- let(:full_body) { "" }
9
- let(:meta_object) { nil }
10
-
11
- subject {
12
- described_class.new(
13
- client: client,
14
- status: status,
15
- headers: headers,
16
- data: data,
17
- full_body: full_body,
18
- meta: meta_object,
19
- )
20
- }
21
-
22
- describe "self.unpack" do
23
- let(:body) { "" }
24
- let(:success) { true }
25
-
26
- let(:response) {
27
- OpenStruct.new(
28
- body: body,
29
- status: status,
30
- headers: headers,
31
- success?: success,
32
- )
33
- }
34
-
35
- it "passes the client supplied" do
36
- object = described_class.unpack(:some_client) { response }
37
-
38
- expect(object.client).to eq :some_client
39
- end
40
-
41
- it "passes the response status" do
42
- object = described_class.unpack(:client) { response }
43
-
44
- expect(object.status).to eq status
45
- end
46
-
47
- it "passes the response headers" do
48
- object = described_class.unpack(:client) { response }
49
-
50
- expect(object.headers).to eq headers
51
- end
52
-
53
- context "with an empty body" do
54
- let(:body) { "" }
55
-
56
- it "without key" do
57
- object = described_class.unpack(client) { response }
58
-
59
- expect(object.data).to eq ""
60
- expect(object.full_body).to eq ""
61
- expect(object.meta).to eq nil
62
- end
63
-
64
- it "ignores key if supplied" do
65
- object = described_class.unpack(client, key: :key) { response }
66
-
67
- expect(object.data).to eq ""
68
- expect(object.full_body).to eq ""
69
- expect(object.meta).to eq nil
70
- end
71
- end
72
-
73
- context "with a nil body" do
74
- let(:body) { nil }
75
-
76
- it "without key" do
77
- object = described_class.unpack(client) { response }
78
-
79
- expect(object.data).to eq nil
80
- expect(object.full_body).to eq nil
81
- expect(object.meta).to eq nil
82
- end
83
-
84
- it "ignores key if supplied" do
85
- object = described_class.unpack(client, key: :key) { response }
86
-
87
- expect(object.data).to eq nil
88
- expect(object.full_body).to eq nil
89
- expect(object.meta).to eq nil
90
- end
91
- end
92
-
93
- context "with a string body" do
94
- let(:body) { "this is a string body, probably due to an error" }
95
-
96
- it "without key" do
97
- object = described_class.unpack(client) { response }
98
-
99
- expect(object.data).to eq body
100
- expect(object.full_body).to eq body
101
- expect(object.meta).to eq nil
102
- end
103
-
104
- it "ignores key if supplied" do
105
- object = described_class.unpack(client, key: :key) { response }
106
-
107
- expect(object.data).to eq body
108
- expect(object.full_body).to eq body
109
- expect(object.meta).to eq nil
110
- end
111
- end
112
-
113
- context "with an json (array) body" do
114
- let(:body) {
115
- [{key: :value}]
116
- }
117
-
118
- it "without key" do
119
- object = described_class.unpack(client) { response }
120
-
121
- expect(object.data).to eq body
122
- expect(object.full_body).to eq body
123
- expect(object.meta).to eq nil
124
- end
125
-
126
- it "ignores key if supplied" do
127
- object = described_class.unpack(client, key: :root) { response }
128
-
129
- expect(object.data).to eq body
130
- expect(object.full_body).to eq body
131
- expect(object.meta).to eq nil
132
- end
133
- end
134
-
135
- context "with a json (hash) body" do
136
- let(:body) {
137
- {root: {key: :value}}
138
- }
139
-
140
- it "without key" do
141
- object = described_class.unpack(client) { response }
142
-
143
- expect(object.data).to eq body
144
- expect(object.full_body).to eq body
145
- expect(object.meta).to eq nil
146
- end
147
-
148
- it "with valid key" do
149
- object = described_class.unpack(client, key: :root) { response }
150
-
151
- expect(object.data).to eq({key: :value})
152
- expect(object.full_body).to eq body
153
- expect(object.meta).to eq nil
154
- end
155
-
156
- it "with invalid key" do
157
- object = described_class.unpack(client, key: :other) { response }
158
-
159
- expect(object.data).to eq nil
160
- expect(object.full_body).to eq body
161
- expect(object.meta).to eq nil
162
- end
163
-
164
- it "with valid keys" do
165
- object = described_class.unpack(client, keys: [:root, :key]) { response }
166
-
167
- expect(object.data).to eq(:value)
168
- expect(object.full_body).to eq body
169
- expect(object.meta).to eq nil
170
- end
171
-
172
- it "with invalid keys" do
173
- object = described_class.unpack(client, keys: [:root, :other]) { response }
174
-
175
- expect(object.data).to eq nil
176
- expect(object.full_body).to eq body
177
- expect(object.meta).to eq nil
178
- end
179
-
180
- context "with meta" do
181
- let(:body) {
182
- {root: {key: :value}, meta: {meta1: :value}}
183
- }
184
-
185
- it "extracts the meta object" do
186
- object = described_class.unpack(client) { response }
187
-
188
- expect(object.meta).to eq({meta1: :value})
189
- end
190
- end
191
- end
192
-
193
- context "with an error response" do
194
- let(:success) { false }
195
- let(:body) { {root: {key: :value}} }
196
-
197
- it "does not dig in the response hash, even with a valid key" do
198
- object = described_class.unpack(client, key: :root) { response }
199
-
200
- expect(object.data).to eq body
201
- expect(object.full_body).to eq body
202
- expect(object.meta).to eq nil
203
- end
204
- end
205
- end
206
-
207
- describe "successful?" do
208
- context "is true when 2XX" do
209
- let(:status) { 200 }
210
- it { expect(subject.successful?).to be true }
211
- end
212
-
213
- context "is false when 3XX" do
214
- let(:status) { 300 }
215
- it { expect(subject.successful?).to be false }
216
- end
217
-
218
- context "is false when 4XX" do
219
- let(:status) { 400 }
220
- it { expect(subject.successful?).to be false }
221
- end
222
-
223
- context "is false when 5XX" do
224
- let(:status) { 500 }
225
- it { expect(subject.successful?).to be false }
226
- end
227
- end
228
-
229
- describe "paginated?" do
230
- context "with pagination metadata" do
231
- let(:meta_object) {
232
- {pagination: {page: 1}}
233
- }
234
-
235
- it { expect(subject.paginated?).to be true }
236
- end
237
-
238
- context "without pagination metadata" do
239
- let(:meta_object) {
240
- {messages: []}
241
- }
242
-
243
- it { expect(subject.paginated?).to be false }
244
- end
245
- end
246
-
247
- describe "operation" do
248
- context "with an operation url" do
249
- before do
250
- load_meta!(api: :regional, folder: :operations)
251
- register_stubs!("find-200", api: :regional, folder: :operations)
252
- end
253
-
254
- let(:url) {
255
- path = "/apps/#{meta[:app_id]}/operations/#{meta[:id]}"
256
- File.join(Scalingo::ENDPOINTS[:regional], path)
257
- }
258
-
259
- let(:headers) {
260
- {location: url}
261
- }
262
-
263
- it { expect(subject.operation?).to be true }
264
- it { expect(subject.operation_url).to eq url }
265
-
266
- it "can request the operation" do
267
- response = subject.operation
268
-
269
- expect(response).to be_successful
270
- expect(response.data[:id]).to be_present
271
- expect(response.data[:status]).to be_present
272
- expect(response.data[:type]).to be_present
273
- end
274
-
275
- it "delegates the operation to the given client" do
276
- mock = double
277
-
278
- expect(subject.client).to receive(:operations).and_return(mock)
279
- expect(mock).to receive(:get).with(url).and_return(:response)
280
-
281
- expect(subject.operation).to eq :response
282
- end
283
-
284
- context "when the client doesn't know about operations" do
285
- let(:client) { auth }
286
-
287
- it "fails silently" do
288
- expect(subject.operation).to eq nil
289
- end
290
- end
291
- end
292
-
293
- context "without an operation url" do
294
- let(:meta_object) { {} }
295
-
296
- it { expect(subject.operation?).to be false }
297
- it { expect(subject.operation_url).to eq nil }
298
- it { expect(subject.operation).to eq nil }
299
- end
300
- end
301
- end
@@ -1,58 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe Scalingo::Auth::Keys do
4
- describe_method "all" do
5
- let(:stub_pattern) { "all-200" }
6
-
7
- it_behaves_like "a collection response"
8
- it_behaves_like "a non-paginated collection"
9
- end
10
-
11
- describe_method "create" do
12
- context "success" do
13
- let(:arguments) { meta[:create][:valid] }
14
- let(:stub_pattern) { "create-201" }
15
-
16
- it_behaves_like "a singular object response", 201
17
- end
18
-
19
- context "unprocessable" do
20
- let(:arguments) { meta[:create][:invalid] }
21
- let(:stub_pattern) { "create-422" }
22
-
23
- it_behaves_like "an unprocessable request"
24
- end
25
- end
26
-
27
- describe_method "show" do
28
- context "success" do
29
- let(:arguments) { meta[:id] }
30
- let(:stub_pattern) { "show-200" }
31
-
32
- it_behaves_like "a singular object response"
33
- end
34
-
35
- context "not found" do
36
- let(:arguments) { meta[:not_found_id] }
37
- let(:stub_pattern) { "show-404" }
38
-
39
- it_behaves_like "a not found response"
40
- end
41
- end
42
-
43
- describe_method "destroy" do
44
- context "success" do
45
- let(:arguments) { meta[:id] }
46
- let(:stub_pattern) { "destroy-204" }
47
-
48
- it_behaves_like "an empty response"
49
- end
50
-
51
- context "not found" do
52
- let(:arguments) { meta[:not_found_id] }
53
- let(:stub_pattern) { "destroy-404" }
54
-
55
- it_behaves_like "a not found response"
56
- end
57
- end
58
- end