codeclimate-services 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +13 -0
  5. data/Gemfile +7 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +121 -0
  8. data/Rakefile +11 -0
  9. data/bin/bundler +16 -0
  10. data/bin/coderay +16 -0
  11. data/bin/nokogiri +16 -0
  12. data/bin/pry +16 -0
  13. data/bin/rake +16 -0
  14. data/codeclimate-services.gemspec +29 -0
  15. data/config/cacert.pem +4026 -0
  16. data/config/load.rb +4 -0
  17. data/lib/axiom/types/password.rb +7 -0
  18. data/lib/cc/formatters/linked_formatter.rb +60 -0
  19. data/lib/cc/formatters/plain_formatter.rb +36 -0
  20. data/lib/cc/formatters/snapshot_formatter.rb +101 -0
  21. data/lib/cc/formatters/ticket_formatter.rb +27 -0
  22. data/lib/cc/helpers/coverage_helper.rb +25 -0
  23. data/lib/cc/helpers/issue_helper.rb +9 -0
  24. data/lib/cc/helpers/quality_helper.rb +44 -0
  25. data/lib/cc/helpers/vulnerability_helper.rb +31 -0
  26. data/lib/cc/presenters/github_pull_requests_presenter.rb +54 -0
  27. data/lib/cc/service/config.rb +4 -0
  28. data/lib/cc/service/formatter.rb +34 -0
  29. data/lib/cc/service/helper.rb +54 -0
  30. data/lib/cc/service/http.rb +87 -0
  31. data/lib/cc/service/invocation/invocation_chain.rb +15 -0
  32. data/lib/cc/service/invocation/with_error_handling.rb +45 -0
  33. data/lib/cc/service/invocation/with_metrics.rb +37 -0
  34. data/lib/cc/service/invocation/with_retries.rb +17 -0
  35. data/lib/cc/service/invocation/with_return_values.rb +18 -0
  36. data/lib/cc/service/invocation.rb +57 -0
  37. data/lib/cc/service/response_check.rb +42 -0
  38. data/lib/cc/service.rb +127 -0
  39. data/lib/cc/services/asana.rb +90 -0
  40. data/lib/cc/services/campfire.rb +55 -0
  41. data/lib/cc/services/flowdock.rb +61 -0
  42. data/lib/cc/services/github_issues.rb +80 -0
  43. data/lib/cc/services/github_pull_requests.rb +210 -0
  44. data/lib/cc/services/hipchat.rb +57 -0
  45. data/lib/cc/services/jira.rb +93 -0
  46. data/lib/cc/services/lighthouse.rb +79 -0
  47. data/lib/cc/services/pivotal_tracker.rb +78 -0
  48. data/lib/cc/services/slack.rb +124 -0
  49. data/lib/cc/services/version.rb +5 -0
  50. data/lib/cc/services.rb +9 -0
  51. data/pull_request_test.rb +47 -0
  52. data/service_test.rb +86 -0
  53. data/test/asana_test.rb +85 -0
  54. data/test/axiom/types/password_test.rb +22 -0
  55. data/test/campfire_test.rb +144 -0
  56. data/test/fixtures.rb +68 -0
  57. data/test/flowdock_test.rb +148 -0
  58. data/test/formatters/snapshot_formatter_test.rb +47 -0
  59. data/test/github_issues_test.rb +96 -0
  60. data/test/github_pull_requests_test.rb +293 -0
  61. data/test/helper.rb +50 -0
  62. data/test/hipchat_test.rb +130 -0
  63. data/test/invocation_error_handling_test.rb +51 -0
  64. data/test/invocation_return_values_test.rb +21 -0
  65. data/test/invocation_test.rb +167 -0
  66. data/test/jira_test.rb +80 -0
  67. data/test/lighthouse_test.rb +74 -0
  68. data/test/pivotal_tracker_test.rb +73 -0
  69. data/test/presenters/github_pull_requests_presenter_test.rb +49 -0
  70. data/test/service_test.rb +63 -0
  71. data/test/slack_test.rb +222 -0
  72. data/test/support/fake_logger.rb +11 -0
  73. data/test/with_metrics_test.rb +19 -0
  74. metadata +263 -0
@@ -0,0 +1,222 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../helper', __FILE__)
4
+
5
+ class TestSlack < CC::Service::TestCase
6
+ def test_test_hook
7
+ assert_slack_receives(
8
+ nil,
9
+ { name: "test", repo_name: "rails" },
10
+ "[rails] This is a test of the Slack service hook"
11
+ )
12
+ end
13
+
14
+ def test_coverage_improved
15
+ e = event(:coverage, to: 90.2, from: 80)
16
+
17
+ assert_slack_receives("#38ae6f", e, [
18
+ "[Example]",
19
+ "<https://codeclimate.com/repos/1/feed|Test coverage>",
20
+ "has improved to 90.2% (+10.2%)",
21
+ "(<https://codeclimate.com/repos/1/compare|Compare>)"
22
+ ].join(" "))
23
+ end
24
+
25
+ def test_coverage_declined
26
+ e = event(:coverage, to: 88.6, from: 94.6)
27
+
28
+ assert_slack_receives("#ed2f00", e, [
29
+ "[Example]",
30
+ "<https://codeclimate.com/repos/1/feed|Test coverage>",
31
+ "has declined to 88.6% (-6.0%)",
32
+ "(<https://codeclimate.com/repos/1/compare|Compare>)"
33
+ ].join(" "))
34
+ end
35
+
36
+ def test_single_vulnerability
37
+ e = event(:vulnerability, vulnerabilities: [
38
+ { "warning_type" => "critical" }
39
+ ])
40
+
41
+ assert_slack_receives(nil, e, [
42
+ "[Example]",
43
+ "New <https://codeclimate.com/repos/1/feed|critical>",
44
+ "issue found",
45
+ ].join(" "))
46
+ end
47
+
48
+ def test_single_vulnerability_with_location
49
+ e = event(:vulnerability, vulnerabilities: [{
50
+ "warning_type" => "critical",
51
+ "location" => "app/user.rb line 120"
52
+ }])
53
+
54
+ assert_slack_receives(nil, e, [
55
+ "[Example]",
56
+ "New <https://codeclimate.com/repos/1/feed|critical>",
57
+ "issue found in app/user.rb line 120",
58
+ ].join(" "))
59
+ end
60
+
61
+ def test_multiple_vulnerabilities
62
+ e = event(:vulnerability, warning_type: "critical", vulnerabilities: [{
63
+ "warning_type" => "unused",
64
+ "location" => "unused"
65
+ }, {
66
+ "warning_type" => "unused",
67
+ "location" => "unused"
68
+ }])
69
+
70
+ assert_slack_receives(nil, e, [
71
+ "[Example]",
72
+ "2 new <https://codeclimate.com/repos/1/feed|critical>",
73
+ "issues found",
74
+ ].join(" "))
75
+ end
76
+
77
+ def test_quality_alert_with_new_constants
78
+ data = { "name" => "snapshot", "repo_name" => "Rails",
79
+ "new_constants" => [{"name" => "Foo", "to" => {"rating" => "D"}}, {"name" => "bar.js", "to" => {"rating" => "F"}}],
80
+ "changed_constants" => [],
81
+ "compare_url" => "https://codeclimate.com/repos/1/compare/a...z" }
82
+
83
+ response = assert_slack_receives(CC::Service::Slack::RED_HEX, data,
84
+ """Quality alert triggered for *Rails* (<https://codeclimate.com/repos/1/compare/a...z|Compare>)
85
+
86
+ • _Foo_ was just created and is a *D*
87
+ • _bar.js_ was just created and is an *F*""")
88
+
89
+ assert response[:ok]
90
+ end
91
+
92
+ def test_quality_alert_with_new_constants_and_declined_constants
93
+ data = { "name" => "snapshot", "repo_name" => "Rails",
94
+ "new_constants" => [{"name" => "Foo", "to" => {"rating" => "D"}}],
95
+ "changed_constants" => [{"name" => "bar.js", "from" => {"rating" => "A"}, "to" => {"rating" => "F"}}],
96
+ "compare_url" => "https://codeclimate.com/repos/1/compare/a...z" }
97
+
98
+ assert_slack_receives(CC::Service::Slack::RED_HEX, data,
99
+ """Quality alert triggered for *Rails* (<https://codeclimate.com/repos/1/compare/a...z|Compare>)
100
+
101
+ • _Foo_ was just created and is a *D*
102
+ • _bar.js_ just declined from an *A* to an *F*""")
103
+ end
104
+
105
+ def test_quality_alert_with_new_constants_and_declined_constants_overflown
106
+ data = { "name" => "snapshot", "repo_name" => "Rails",
107
+ "new_constants" => [{"name" => "Foo", "to" => {"rating" => "D"}}],
108
+ "changed_constants" => [
109
+ {"name" => "bar.js", "from" => {"rating" => "A"}, "to" => {"rating" => "F"}},
110
+ {"name" => "baz.js", "from" => {"rating" => "B"}, "to" => {"rating" => "D"}},
111
+ {"name" => "Qux", "from" => {"rating" => "A"}, "to" => {"rating" => "D"}}
112
+ ],
113
+ "compare_url" => "https://codeclimate.com/repos/1/compare/a...z",
114
+ "details_url" => "https://codeclimate.com/repos/1/feed"
115
+ }
116
+
117
+
118
+ assert_slack_receives(CC::Service::Slack::RED_HEX, data,
119
+ """Quality alert triggered for *Rails* (<https://codeclimate.com/repos/1/compare/a...z|Compare>)
120
+
121
+ • _Foo_ was just created and is a *D*
122
+ • _bar.js_ just declined from an *A* to an *F*
123
+ • _baz.js_ just declined from a *B* to a *D*
124
+
125
+ And <https://codeclimate.com/repos/1/feed|1 other change>""")
126
+ end
127
+
128
+ def test_quality_improvements
129
+ data = { "name" => "snapshot", "repo_name" => "Rails",
130
+ "new_constants" => [],
131
+ "changed_constants" => [
132
+ {"name" => "bar.js", "from" => {"rating" => "F"}, "to" => {"rating" => "A"}},
133
+ ],
134
+ "compare_url" => "https://codeclimate.com/repos/1/compare/a...z",
135
+ "details_url" => "https://codeclimate.com/repos/1/feed"
136
+ }
137
+
138
+
139
+ assert_slack_receives(CC::Service::Slack::GREEN_HEX, data,
140
+ """Quality improvements in *Rails* (<https://codeclimate.com/repos/1/compare/a...z|Compare>)
141
+
142
+ • _bar.js_ just improved from an *F* to an *A*""")
143
+ end
144
+
145
+ def test_quality_improvements_overflown
146
+ data = { "name" => "snapshot", "repo_name" => "Rails",
147
+ "new_constants" => [],
148
+ "changed_constants" => [
149
+ {"name" => "Foo", "from" => {"rating" => "F"}, "to" => {"rating" => "A"}},
150
+ {"name" => "bar.js", "from" => {"rating" => "D"}, "to" => {"rating" => "B"}},
151
+ {"name" => "baz.js", "from" => {"rating" => "D"}, "to" => {"rating" => "A"}},
152
+ {"name" => "Qux", "from" => {"rating" => "F"}, "to" => {"rating" => "A"}},
153
+ ],
154
+ "compare_url" => "https://codeclimate.com/repos/1/compare/a...z",
155
+ "details_url" => "https://codeclimate.com/repos/1/feed"
156
+ }
157
+
158
+
159
+ assert_slack_receives(CC::Service::Slack::GREEN_HEX, data,
160
+ """Quality improvements in *Rails* (<https://codeclimate.com/repos/1/compare/a...z|Compare>)
161
+
162
+ • _Foo_ just improved from an *F* to an *A*
163
+ • _bar.js_ just improved from a *D* to a *B*
164
+ • _baz.js_ just improved from a *D* to an *A*
165
+
166
+ And <https://codeclimate.com/repos/1/feed|1 other improvement>""")
167
+ end
168
+
169
+ def test_received_success
170
+ response = assert_slack_receives(
171
+ nil,
172
+ { name: "test", repo_name: "rails" },
173
+ "[rails] This is a test of the Slack service hook"
174
+ )
175
+ assert_true response[:ok]
176
+ assert_equal "Test message sent", response[:message]
177
+ end
178
+
179
+ def test_receive_test
180
+ @stubs.post '/token' do |env|
181
+ [200, {}, 'ok']
182
+ end
183
+
184
+ response = receive_event(name: "test")
185
+
186
+ assert_equal "Test message sent", response[:message]
187
+ end
188
+
189
+ def test_no_changes_in_snapshot
190
+ data = { "name" => "snapshot", "repo_name" => "Rails",
191
+ "new_constants" => [],
192
+ "changed_constants" => [],
193
+ }
194
+ response = receive_event(data)
195
+
196
+ assert_equal false, response[:ok]
197
+ assert response[:ignored]
198
+ end
199
+
200
+ private
201
+
202
+ def assert_slack_receives(color, event_data, expected_body)
203
+ @stubs.post '/token' do |env|
204
+ body = JSON.parse(env[:body])
205
+ attachment = body["attachments"].first
206
+ field = attachment["fields"].first
207
+ assert_equal color, attachment["color"] # may be nil
208
+ assert_equal expected_body, attachment["fallback"]
209
+ assert_equal expected_body, field["value"]
210
+ [200, {}, 'ok']
211
+ end
212
+ receive_event(event_data)
213
+ end
214
+
215
+ def receive_event(event_data = nil)
216
+ receive(
217
+ CC::Service::Slack,
218
+ { webhook_url: "http://api.slack.com/token", channel: "#general" },
219
+ event_data || event(:quality, from: "C", to: "D")
220
+ )
221
+ end
222
+ end
@@ -0,0 +1,11 @@
1
+ class FakeLogger
2
+ attr_reader :logged_errors
3
+
4
+ def initialize
5
+ @logged_errors = []
6
+ end
7
+
8
+ def error(message)
9
+ @logged_errors << message
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+
3
+ require File.expand_path('../helper', __FILE__)
4
+
5
+ class WithMetrics < CC::Service::TestCase
6
+
7
+ class FakeInvocation
8
+ def call
9
+ raise CC::Service::HTTPError.new("Whoa", {})
10
+ end
11
+ end
12
+
13
+ def test_statsd_error_key
14
+ statsd = Object.new
15
+ statsd.stubs(:timing)
16
+ statsd.expects("increment").with("services.errors.githubpullrequests.cc-service-http_error")
17
+ CC::Service::Invocation::WithMetrics.new(FakeInvocation.new, statsd, "githubpullrequests").call rescue CC::Service::HTTPError
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,263 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: codeclimate-services
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Bryan Helmkamp
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.8
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.8
27
+ - !ruby/object:Gem::Dependency
28
+ name: virtus
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: nokogiri
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.6.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.6.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: activemodel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 1.6.2
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.6.2
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: test-unit
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: mocha
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Service classes for Code Climate
140
+ email:
141
+ - bryan@brynary.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - .gitignore
147
+ - .ruby-version
148
+ - .travis.yml
149
+ - Gemfile
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - bin/bundler
154
+ - bin/coderay
155
+ - bin/nokogiri
156
+ - bin/pry
157
+ - bin/rake
158
+ - codeclimate-services.gemspec
159
+ - config/cacert.pem
160
+ - config/load.rb
161
+ - lib/axiom/types/password.rb
162
+ - lib/cc/formatters/linked_formatter.rb
163
+ - lib/cc/formatters/plain_formatter.rb
164
+ - lib/cc/formatters/snapshot_formatter.rb
165
+ - lib/cc/formatters/ticket_formatter.rb
166
+ - lib/cc/helpers/coverage_helper.rb
167
+ - lib/cc/helpers/issue_helper.rb
168
+ - lib/cc/helpers/quality_helper.rb
169
+ - lib/cc/helpers/vulnerability_helper.rb
170
+ - lib/cc/presenters/github_pull_requests_presenter.rb
171
+ - lib/cc/service.rb
172
+ - lib/cc/service/config.rb
173
+ - lib/cc/service/formatter.rb
174
+ - lib/cc/service/helper.rb
175
+ - lib/cc/service/http.rb
176
+ - lib/cc/service/invocation.rb
177
+ - lib/cc/service/invocation/invocation_chain.rb
178
+ - lib/cc/service/invocation/with_error_handling.rb
179
+ - lib/cc/service/invocation/with_metrics.rb
180
+ - lib/cc/service/invocation/with_retries.rb
181
+ - lib/cc/service/invocation/with_return_values.rb
182
+ - lib/cc/service/response_check.rb
183
+ - lib/cc/services.rb
184
+ - lib/cc/services/asana.rb
185
+ - lib/cc/services/campfire.rb
186
+ - lib/cc/services/flowdock.rb
187
+ - lib/cc/services/github_issues.rb
188
+ - lib/cc/services/github_pull_requests.rb
189
+ - lib/cc/services/hipchat.rb
190
+ - lib/cc/services/jira.rb
191
+ - lib/cc/services/lighthouse.rb
192
+ - lib/cc/services/pivotal_tracker.rb
193
+ - lib/cc/services/slack.rb
194
+ - lib/cc/services/version.rb
195
+ - pull_request_test.rb
196
+ - service_test.rb
197
+ - test/asana_test.rb
198
+ - test/axiom/types/password_test.rb
199
+ - test/campfire_test.rb
200
+ - test/fixtures.rb
201
+ - test/flowdock_test.rb
202
+ - test/formatters/snapshot_formatter_test.rb
203
+ - test/github_issues_test.rb
204
+ - test/github_pull_requests_test.rb
205
+ - test/helper.rb
206
+ - test/hipchat_test.rb
207
+ - test/invocation_error_handling_test.rb
208
+ - test/invocation_return_values_test.rb
209
+ - test/invocation_test.rb
210
+ - test/jira_test.rb
211
+ - test/lighthouse_test.rb
212
+ - test/pivotal_tracker_test.rb
213
+ - test/presenters/github_pull_requests_presenter_test.rb
214
+ - test/service_test.rb
215
+ - test/slack_test.rb
216
+ - test/support/fake_logger.rb
217
+ - test/with_metrics_test.rb
218
+ homepage: ''
219
+ licenses:
220
+ - MIT
221
+ metadata: {}
222
+ post_install_message:
223
+ rdoc_options: []
224
+ require_paths:
225
+ - lib
226
+ required_ruby_version: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - '>='
229
+ - !ruby/object:Gem::Version
230
+ version: '0'
231
+ required_rubygems_version: !ruby/object:Gem::Requirement
232
+ requirements:
233
+ - - '>='
234
+ - !ruby/object:Gem::Version
235
+ version: '0'
236
+ requirements: []
237
+ rubyforge_project:
238
+ rubygems_version: 2.4.7
239
+ signing_key:
240
+ specification_version: 4
241
+ summary: Service classes for Code Climate
242
+ test_files:
243
+ - test/asana_test.rb
244
+ - test/axiom/types/password_test.rb
245
+ - test/campfire_test.rb
246
+ - test/fixtures.rb
247
+ - test/flowdock_test.rb
248
+ - test/formatters/snapshot_formatter_test.rb
249
+ - test/github_issues_test.rb
250
+ - test/github_pull_requests_test.rb
251
+ - test/helper.rb
252
+ - test/hipchat_test.rb
253
+ - test/invocation_error_handling_test.rb
254
+ - test/invocation_return_values_test.rb
255
+ - test/invocation_test.rb
256
+ - test/jira_test.rb
257
+ - test/lighthouse_test.rb
258
+ - test/pivotal_tracker_test.rb
259
+ - test/presenters/github_pull_requests_presenter_test.rb
260
+ - test/service_test.rb
261
+ - test/slack_test.rb
262
+ - test/support/fake_logger.rb
263
+ - test/with_metrics_test.rb