qiita_team_services 0.3.1

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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +27 -0
  5. data/.travis.yml +11 -0
  6. data/CHANGELOG.md +7 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE +22 -0
  9. data/README.md +5 -0
  10. data/Rakefile +26 -0
  11. data/config/locales/en.yml +31 -0
  12. data/config/locales/ja.yml +32 -0
  13. data/lib/qiita/team/services/engine.rb +6 -0
  14. data/lib/qiita/team/services/errors.rb +7 -0
  15. data/lib/qiita/team/services/events/base.rb +47 -0
  16. data/lib/qiita/team/services/events/item_became_coediting.rb +10 -0
  17. data/lib/qiita/team/services/events/item_comment_created.rb +17 -0
  18. data/lib/qiita/team/services/events/item_comment_destroyed.rb +17 -0
  19. data/lib/qiita/team/services/events/item_comment_updated.rb +17 -0
  20. data/lib/qiita/team/services/events/item_created.rb +10 -0
  21. data/lib/qiita/team/services/events/item_destroyed.rb +10 -0
  22. data/lib/qiita/team/services/events/item_updated.rb +10 -0
  23. data/lib/qiita/team/services/events/project_activated.rb +10 -0
  24. data/lib/qiita/team/services/events/project_archived.rb +10 -0
  25. data/lib/qiita/team/services/events/project_comment_created.rb +19 -0
  26. data/lib/qiita/team/services/events/project_comment_destroyed.rb +19 -0
  27. data/lib/qiita/team/services/events/project_comment_updated.rb +19 -0
  28. data/lib/qiita/team/services/events/project_created.rb +10 -0
  29. data/lib/qiita/team/services/events/project_destroyed.rb +10 -0
  30. data/lib/qiita/team/services/events/project_updated.rb +10 -0
  31. data/lib/qiita/team/services/events/team_member_added.rb +12 -0
  32. data/lib/qiita/team/services/events/team_member_removed.rb +12 -0
  33. data/lib/qiita/team/services/events.rb +28 -0
  34. data/lib/qiita/team/services/hooks/base.rb +45 -0
  35. data/lib/qiita/team/services/hooks/chatwork_v1.rb +149 -0
  36. data/lib/qiita/team/services/hooks/concerns/event_handlable.rb +49 -0
  37. data/lib/qiita/team/services/hooks/concerns/http_client.rb +74 -0
  38. data/lib/qiita/team/services/hooks/concerns/persistable.rb +64 -0
  39. data/lib/qiita/team/services/hooks/concerns/service.rb +31 -0
  40. data/lib/qiita/team/services/hooks/concerns/slack.rb +338 -0
  41. data/lib/qiita/team/services/hooks/hipchat_v1.rb +143 -0
  42. data/lib/qiita/team/services/hooks/slack_v1.rb +25 -0
  43. data/lib/qiita/team/services/hooks/slack_v2.rb +19 -0
  44. data/lib/qiita/team/services/hooks/webhook.rb +193 -0
  45. data/lib/qiita/team/services/hooks.rb +25 -0
  46. data/lib/qiita/team/services/properties/base.rb +20 -0
  47. data/lib/qiita/team/services/properties/boolean_property.rb +12 -0
  48. data/lib/qiita/team/services/properties/string_property.rb +12 -0
  49. data/lib/qiita/team/services/properties.rb +21 -0
  50. data/lib/qiita/team/services/resources/README.md +177 -0
  51. data/lib/qiita/team/services/templates/chatwork_v1.html.erb +25 -0
  52. data/lib/qiita/team/services/templates/hipchat_v1.html.erb +58 -0
  53. data/lib/qiita/team/services/templates/slack_v1.html.erb +54 -0
  54. data/lib/qiita/team/services/templates/slack_v2.html.erb +44 -0
  55. data/lib/qiita/team/services/templates/webhook.html.erb +25 -0
  56. data/lib/qiita/team/services/version.rb +3 -0
  57. data/lib/qiita_team_services.rb +34 -0
  58. data/qiita_team_services.gemspec +42 -0
  59. data/spec/hooks/chatwork_v1_spec.rb +118 -0
  60. data/spec/hooks/hipchat_v1_spec.rb +139 -0
  61. data/spec/hooks/slack_v1_spec.rb +55 -0
  62. data/spec/hooks/slack_v2_spec.rb +50 -0
  63. data/spec/hooks/webhook_spec.rb +465 -0
  64. data/spec/spec_helper.rb +17 -0
  65. data/spec/support/factories/comments.rb +21 -0
  66. data/spec/support/factories/items.rb +26 -0
  67. data/spec/support/factories/projects.rb +17 -0
  68. data/spec/support/factories/taggings.rb +9 -0
  69. data/spec/support/factories/teams.rb +9 -0
  70. data/spec/support/factories/users.rb +11 -0
  71. data/spec/support/factory_girl.rb +13 -0
  72. data/spec/support/helpers/event_helper.rb +49 -0
  73. data/spec/support/helpers/hook_helper.rb +33 -0
  74. data/spec/support/helpers/http_client_stub_helper.rb +19 -0
  75. data/spec/support/helpers/slack_hook_helper.rb +104 -0
  76. data/spec/support/matchers/match_slack_attachments_request.rb +7 -0
  77. data/spec/support/resources/base.rb +23 -0
  78. data/spec/support/resources/comment.rb +29 -0
  79. data/spec/support/resources/item.rb +53 -0
  80. data/spec/support/resources/project.rb +45 -0
  81. data/spec/support/resources/tagging.rb +15 -0
  82. data/spec/support/resources/team.rb +11 -0
  83. data/spec/support/resources/user.rb +17 -0
  84. metadata +323 -0
@@ -0,0 +1,465 @@
1
+ describe Qiita::Team::Services::Hooks::Webhook, :versioning do
2
+ let(:hook) do
3
+ described_class.new(properties)
4
+ end
5
+
6
+ let(:properties) do
7
+ {
8
+ "url" => url,
9
+ "token" => token,
10
+ }
11
+ end
12
+
13
+ let(:url) do
14
+ FFaker::Internet.http_url
15
+ end
16
+
17
+ let(:token) do
18
+ described_class.generate_token
19
+ end
20
+
21
+ let(:event) do
22
+ Qiita::Team::Services::Events.create(event_name, resource, user, team)
23
+ end
24
+
25
+ let(:user) do
26
+ build(:user)
27
+ end
28
+
29
+ let(:team) do
30
+ build(:team)
31
+ end
32
+
33
+ describe "#item_created" do
34
+ subject do
35
+ hook.item_created(event)
36
+ end
37
+
38
+ let(:event_name) do
39
+ "item_created"
40
+ end
41
+
42
+ let(:resource) do
43
+ build(:item)
44
+ end
45
+
46
+ it "sends webhook" do
47
+ request = stub_request(:post, url).with(
48
+ body: {
49
+ action: "created",
50
+ model: "item",
51
+ item: hash_including(
52
+ "body" => kind_of(String),
53
+ "coediting" => false,
54
+ "comment_count" => kind_of(Integer),
55
+ "created_at_as_seconds" => kind_of(Integer),
56
+ "created_at_in_words" => kind_of(String),
57
+ "created_at" => kind_of(String),
58
+ "id" => kind_of(Integer),
59
+ "lgtm_count" => kind_of(Integer),
60
+ "raw_body" => kind_of(String),
61
+ "stock_count" => kind_of(Integer),
62
+ "stock_users" => [],
63
+ "tags" => [
64
+ {
65
+ "name" => kind_of(String),
66
+ "url_name" => kind_of(String),
67
+ "versions" => kind_of(Array),
68
+ },
69
+ ],
70
+ "title" => kind_of(String),
71
+ "updated_at" => kind_of(String),
72
+ "updated_at_in_words" => kind_of(String),
73
+ "url" => kind_of(String),
74
+ "user" => {
75
+ "id" => kind_of(Integer),
76
+ "profile_image_url" => kind_of(String),
77
+ "url_name" => kind_of(String),
78
+ },
79
+ "uuid" => kind_of(String),
80
+ ),
81
+ user: {
82
+ "id" => kind_of(Integer),
83
+ "profile_image_url" => kind_of(String),
84
+ "url_name" => kind_of(String),
85
+ },
86
+ },
87
+ headers: {
88
+ "Content-Type" => "application/json",
89
+ "User-Agent" => "Qiita:Team",
90
+ "X-Qiita-Event-Model" => "item",
91
+ "X-Qiita-Token" => token,
92
+ },
93
+ )
94
+ subject
95
+ expect(request).to have_been_made
96
+ end
97
+ end
98
+
99
+ describe "#item_updated" do
100
+ subject do
101
+ hook.item_updated(event)
102
+ end
103
+
104
+ let(:event_name) do
105
+ "item_updated"
106
+ end
107
+
108
+ let(:resource) do
109
+ build(:item)
110
+ end
111
+
112
+ it "sends webhook" do
113
+ request = stub_request(:post, url).with(
114
+ body: {
115
+ action: "updated",
116
+ message: kind_of(String),
117
+ model: "item",
118
+ item: kind_of(Hash),
119
+ user: kind_of(Hash),
120
+ },
121
+ )
122
+ subject
123
+ expect(request).to have_been_made
124
+ end
125
+ end
126
+
127
+ describe "#item_destroyed" do
128
+ subject do
129
+ hook.item_destroyed(event)
130
+ end
131
+
132
+ let(:event_name) do
133
+ "item_destroyed"
134
+ end
135
+
136
+ let(:resource) do
137
+ build(:item)
138
+ end
139
+
140
+ it "sends webhook" do
141
+ request = stub_request(:post, url).with(
142
+ body: {
143
+ action: "destroyed",
144
+ model: "item",
145
+ item: kind_of(Hash),
146
+ },
147
+ )
148
+ subject
149
+ expect(request).to have_been_made
150
+ end
151
+ end
152
+
153
+ describe "#item_comment_created" do
154
+ subject do
155
+ hook.item_comment_created(event)
156
+ end
157
+
158
+ let(:event_name) do
159
+ "item_comment_created"
160
+ end
161
+
162
+ let(:resource) do
163
+ build(:comment)
164
+ end
165
+
166
+ it "sends webhook" do
167
+ request = stub_request(:post, url).with(
168
+ body: {
169
+ action: "created",
170
+ model: "comment",
171
+ comment: kind_of(Hash),
172
+ item: kind_of(Hash),
173
+ },
174
+ )
175
+ subject
176
+ expect(request).to have_been_made
177
+ end
178
+ end
179
+
180
+ describe "#item_comment_updated" do
181
+ subject do
182
+ hook.item_comment_updated(event)
183
+ end
184
+
185
+ let(:event_name) do
186
+ "item_comment_updated"
187
+ end
188
+
189
+ let(:resource) do
190
+ build(:comment)
191
+ end
192
+
193
+ it "sends webhook" do
194
+ request = stub_request(:post, url).with(
195
+ body: {
196
+ action: "updated",
197
+ model: "comment",
198
+ comment: kind_of(Hash),
199
+ item: kind_of(Hash),
200
+ },
201
+ )
202
+ subject
203
+ expect(request).to have_been_made
204
+ end
205
+ end
206
+
207
+ describe "#item_comment_destroyed" do
208
+ subject do
209
+ hook.item_comment_destroyed(event)
210
+ end
211
+
212
+ let(:event_name) do
213
+ "item_comment_destroyed"
214
+ end
215
+
216
+ let(:resource) do
217
+ build(:comment)
218
+ end
219
+
220
+ it "sends webhook" do
221
+ request = stub_request(:post, url).with(
222
+ body: {
223
+ action: "destroyed",
224
+ model: "comment",
225
+ comment: kind_of(Hash),
226
+ item: kind_of(Hash),
227
+ },
228
+ )
229
+ subject
230
+ expect(request).to have_been_made
231
+ end
232
+ end
233
+
234
+ describe "#project_comment_created" do
235
+ subject do
236
+ hook.project_comment_created(event)
237
+ end
238
+
239
+ let(:event_name) do
240
+ "project_comment_created"
241
+ end
242
+
243
+ let(:resource) do
244
+ build(:comment)
245
+ end
246
+
247
+ it "sends webhook" do
248
+ request = stub_request(:post, url).with(
249
+ body: {
250
+ action: "created",
251
+ model: "comment",
252
+ comment: kind_of(Hash),
253
+ item: kind_of(Hash),
254
+ },
255
+ )
256
+ subject
257
+ expect(request).to have_been_made
258
+ end
259
+ end
260
+
261
+ describe "#project_comment_updated" do
262
+ subject do
263
+ hook.project_comment_updated(event)
264
+ end
265
+
266
+ let(:event_name) do
267
+ "project_comment_updated"
268
+ end
269
+
270
+ let(:resource) do
271
+ build(:comment)
272
+ end
273
+
274
+ it "sends webhook" do
275
+ request = stub_request(:post, url).with(
276
+ body: {
277
+ action: "updated",
278
+ model: "comment",
279
+ comment: kind_of(Hash),
280
+ item: kind_of(Hash),
281
+ },
282
+ )
283
+ subject
284
+ expect(request).to have_been_made
285
+ end
286
+ end
287
+
288
+ describe "#project_comment_destroyed" do
289
+ subject do
290
+ hook.project_comment_destroyed(event)
291
+ end
292
+
293
+ let(:event_name) do
294
+ "project_comment_destroyed"
295
+ end
296
+
297
+ let(:resource) do
298
+ build(:comment)
299
+ end
300
+
301
+ it "sends webhook" do
302
+ request = stub_request(:post, url).with(
303
+ body: {
304
+ action: "destroyed",
305
+ model: "comment",
306
+ comment: kind_of(Hash),
307
+ item: kind_of(Hash),
308
+ },
309
+ )
310
+ subject
311
+ expect(request).to have_been_made
312
+ end
313
+ end
314
+
315
+ describe "#team_member_added" do
316
+ subject do
317
+ hook.team_member_added(event)
318
+ end
319
+
320
+ let(:event_name) do
321
+ "team_member_added"
322
+ end
323
+
324
+ let(:resource) do
325
+ build(:user)
326
+ end
327
+
328
+ it "sends webhook" do
329
+ request = stub_request(:post, url).with(
330
+ body: {
331
+ action: "added",
332
+ model: "member",
333
+ user: kind_of(Hash),
334
+ },
335
+ )
336
+ subject
337
+ expect(request).to have_been_made
338
+ end
339
+ end
340
+
341
+ describe "#team_member_removed" do
342
+ subject do
343
+ hook.team_member_added(event)
344
+ end
345
+
346
+ let(:event_name) do
347
+ "team_member_removed"
348
+ end
349
+
350
+ let(:resource) do
351
+ build(:user)
352
+ end
353
+
354
+ it "sends webhook" do
355
+ request = stub_request(:post, url).with(
356
+ body: {
357
+ action: "added",
358
+ model: "member",
359
+ user: kind_of(Hash),
360
+ },
361
+ )
362
+ subject
363
+ expect(request).to have_been_made
364
+ end
365
+ end
366
+
367
+ describe "#project_created" do
368
+ subject do
369
+ hook.project_created(event)
370
+ end
371
+
372
+ let(:event_name) do
373
+ "project_created"
374
+ end
375
+
376
+ let(:resource) do
377
+ build(:project)
378
+ end
379
+
380
+ it "sends webhook" do
381
+ request = stub_request(:post, url).with(
382
+ body: {
383
+ action: "created",
384
+ model: "project",
385
+ project: kind_of(Hash),
386
+ user: kind_of(Hash),
387
+ },
388
+ )
389
+ subject
390
+ expect(request).to have_been_made
391
+ end
392
+ end
393
+
394
+ describe "#project_updated" do
395
+ subject do
396
+ hook.project_updated(event)
397
+ end
398
+
399
+ let(:event_name) do
400
+ "project_updated"
401
+ end
402
+
403
+ let(:resource) do
404
+ build(:project)
405
+ end
406
+
407
+ it "sends webhook" do
408
+ request = stub_request(:post, url).with(
409
+ body: {
410
+ action: "updated",
411
+ model: "project",
412
+ message: kind_of(String),
413
+ project: kind_of(Hash),
414
+ user: kind_of(Hash),
415
+ },
416
+ )
417
+ subject
418
+ expect(request).to have_been_made
419
+ end
420
+ end
421
+
422
+ describe "#project_destroyed" do
423
+ subject do
424
+ hook.project_destroyed(event)
425
+ end
426
+
427
+ let(:event_name) do
428
+ "project_destroyed"
429
+ end
430
+
431
+ let(:resource) do
432
+ build(:project)
433
+ end
434
+
435
+ it "sends webhook" do
436
+ request = stub_request(:post, url).with(
437
+ body: {
438
+ action: "destroyed",
439
+ model: "project",
440
+ project: kind_of(Hash),
441
+ },
442
+ )
443
+ subject
444
+ expect(request).to have_been_made
445
+ end
446
+ end
447
+
448
+ describe "#ping" do
449
+ subject do
450
+ hook.ping
451
+ end
452
+
453
+ it "enqueues job to send event" do
454
+ request = stub_request(:post, url).with(
455
+ body: {
456
+ action: "requested",
457
+ message: "ping",
458
+ model: "ping",
459
+ },
460
+ )
461
+ subject
462
+ expect(request).to have_been_made
463
+ end
464
+ end
465
+ end
@@ -0,0 +1,17 @@
1
+ require "ffaker"
2
+ require "pry"
3
+ require "webmock/rspec"
4
+ require "faraday"
5
+ require "qiita_team_services"
6
+
7
+ Dir.glob("spec/support/{helpers,matchers}/*.rb").each do |filepath|
8
+ load filepath
9
+ end
10
+
11
+ require "support/factory_girl"
12
+
13
+ FactoryGirl.define do
14
+ sequence(:id)
15
+ end
16
+
17
+ Faraday.default_adapter = :test
@@ -0,0 +1,21 @@
1
+ require "support/resources/comment"
2
+
3
+ FactoryGirl.define do
4
+ factory :comment, aliases: [:item_comment], class: Qiita::Team::Services::Resources::Comment do
5
+ item
6
+ user { build(:user) }
7
+ id { generate(:id) }
8
+ body "# Example"
9
+ rendered_body "<h1>Example</h1>"
10
+ url { "#{item.url}#comment-#{id}" }
11
+ end
12
+
13
+ factory :project_comment, class: Qiita::Team::Services::Resources::Comment do
14
+ item { build(:project) }
15
+ user { build(:user) }
16
+ id { generate(:id) }
17
+ body "# Example"
18
+ rendered_body "<h1>Example</h1>"
19
+ url { "#{item.url}#comment-#{id}" }
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ require "support/resources/item"
2
+
3
+ FactoryGirl.define do
4
+ factory :item, class: Qiita::Team::Services::Resources::Item do
5
+ body "# Example"
6
+ coediting false
7
+ comment_count 0
8
+ created_at { Time.now }
9
+ created_at_as_seconds { created_at.to_i }
10
+ created_at_in_words "just now"
11
+ editor { build(:user) }
12
+ id { generate(:id) }
13
+ lgtm_count 0
14
+ message { FFaker::Lorem.sentence }
15
+ rendered_body "<h1>Example</h1>"
16
+ stock_count 0
17
+ stock_users []
18
+ tags { [build(:tagging)] }
19
+ title "Example title"
20
+ updated_at { Time.now }
21
+ updated_at_in_words "just now"
22
+ url { "#{build(:team).url}/#{id}" }
23
+ user
24
+ uuid { "4bd431809afb1bb99e4#{generate(:id)}" }
25
+ end
26
+ end
@@ -0,0 +1,17 @@
1
+ require "support/resources/project"
2
+
3
+ FactoryGirl.define do
4
+ factory :project, class: Qiita::Team::Services::Resources::Project do
5
+ user { build(:user) }
6
+ editor { user }
7
+ id { generate(:id) }
8
+ name "Example name"
9
+ body "# Example"
10
+ rendered_body "<h1>Example</h1>"
11
+ message { FFaker::Lorem.sentence }
12
+ url { "#{build(:team).url}/projects/#{id}" }
13
+ archived false
14
+ created_at { Time.now }
15
+ updated_at { Time.now }
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ require "support/resources/tagging"
2
+
3
+ FactoryGirl.define do
4
+ factory :tagging, class: Qiita::Team::Services::Resources::Tagging do
5
+ name "Ruby"
6
+ url_name "ruby"
7
+ versions %w(1.9.3 2.0.0)
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require "support/resources/team"
2
+
3
+ FactoryGirl.define do
4
+ factory :team, class: Qiita::Team::Services::Resources::Team do
5
+ id { generate(:id) }
6
+ name { "name#{id}" }
7
+ url { "https://#{name}.qiita.com" }
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ require "support/resources/user"
2
+
3
+ FactoryGirl.define do
4
+ factory :user, aliases: [:team_member], class: Qiita::Team::Services::Resources::User do
5
+ id { generate(:id) }
6
+ url_name { "url_name#{id}" }
7
+ name { "name#{id}" }
8
+ url { "#{build(:team).url}/#{name}" }
9
+ profile_image_url "http://example.com"
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require "factory_girl"
2
+
3
+ Dir.glob("spec/support/factories/*.rb")
4
+ .map { |filepath| filepath.split("/").last.split(".").first }
5
+ .each { |name| require "support/factories/#{name}" }
6
+
7
+ RSpec.configure do |config|
8
+ config.include FactoryGirl::Syntax::Methods
9
+
10
+ config.before(:suite) do
11
+ FactoryGirl.lint
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ require "active_support/concern"
2
+
3
+ module Qiita::Team::Services
4
+ module Helpers
5
+ module EventHelper
6
+ extend ActiveSupport::Concern
7
+
8
+ {
9
+ item_comment: [
10
+ :created,
11
+ :updated,
12
+ :destroyed,
13
+ ],
14
+ project_comment: [
15
+ :created,
16
+ :updated,
17
+ :destroyed,
18
+ ],
19
+ item: [
20
+ :became_coediting,
21
+ :created,
22
+ :updated,
23
+ :destroyed,
24
+ ],
25
+ project: [
26
+ :activated,
27
+ :archived,
28
+ :created,
29
+ :updated,
30
+ :destroyed,
31
+ ],
32
+ team_member: [
33
+ :added,
34
+ :removed,
35
+ ],
36
+ }.each_pair do |resource_name, action_names|
37
+ action_names.each do |action_name|
38
+ event_name = "#{resource_name}_#{action_name}"
39
+ define_method "#{event_name}_event" do |resource = nil, user = nil, team = nil|
40
+ resource ||= build(resource_name)
41
+ user ||= build(:user)
42
+ team ||= build(:team)
43
+ Events.create(event_name, resource, user, team)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ require "active_support/concern"
2
+ require "action_view/helpers"
3
+
4
+ module Qiita::Team::Services
5
+ module Helpers
6
+ module HookHelper
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ shared_examples "hook" do
11
+ describe ".service_name" do
12
+ subject do
13
+ described_class.service_name
14
+ end
15
+
16
+ it { should be_a String }
17
+ end
18
+
19
+ describe ".render_form" do
20
+ subject do
21
+ extend ActionView::Helpers::FormHelper
22
+ extend ActionView::Helpers::FormTagHelper
23
+ extend ActionView::Helpers::FormOptionsHelper
24
+ described_class.render_form(binding)
25
+ end
26
+
27
+ it { should be_a String }
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ require "active_support/concern"
2
+
3
+ module Qiita::Team::Services
4
+ module Helpers
5
+ module HttpClientStubHelper
6
+ extend ActiveSupport::Concern
7
+
8
+ # @param service [#http_client]
9
+ def get_http_client_stub(service)
10
+ stubs = Faraday::Adapter::Test::Stubs.new
11
+ http_client = Faraday.new do |faraday|
12
+ faraday.adapter :test, stubs
13
+ end
14
+ allow(service).to receive(:http_client).and_return(http_client)
15
+ stubs
16
+ end
17
+ end
18
+ end
19
+ end