chatops-controller 3.0.3

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +204 -0
  3. data/lib/chatops-controller.rb +1 -0
  4. data/lib/chatops.rb +21 -0
  5. data/lib/chatops/controller.rb +209 -0
  6. data/lib/chatops/controller/rspec.rb +5 -0
  7. data/lib/chatops/controller/test_case.rb +5 -0
  8. data/lib/chatops/controller/test_case_helpers.rb +91 -0
  9. data/lib/chatops/controller/version.rb +3 -0
  10. data/spec/dummy/README.rdoc +28 -0
  11. data/spec/dummy/Rakefile +6 -0
  12. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  13. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  14. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  15. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  16. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  17. data/spec/dummy/bin/bundle +3 -0
  18. data/spec/dummy/bin/rails +4 -0
  19. data/spec/dummy/bin/rake +4 -0
  20. data/spec/dummy/bin/setup +29 -0
  21. data/spec/dummy/config.ru +4 -0
  22. data/spec/dummy/config/application.rb +24 -0
  23. data/spec/dummy/config/boot.rb +5 -0
  24. data/spec/dummy/config/database.yml +25 -0
  25. data/spec/dummy/config/environment.rb +5 -0
  26. data/spec/dummy/config/environments/development.rb +41 -0
  27. data/spec/dummy/config/environments/production.rb +79 -0
  28. data/spec/dummy/config/environments/test.rb +46 -0
  29. data/spec/dummy/config/initializers/assets.rb +13 -0
  30. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  31. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  32. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  33. data/spec/dummy/config/initializers/inflections.rb +16 -0
  34. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  35. data/spec/dummy/config/initializers/session_store.rb +3 -0
  36. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  37. data/spec/dummy/config/locales/en.yml +23 -0
  38. data/spec/dummy/config/routes.rb +56 -0
  39. data/spec/dummy/config/secrets.yml +22 -0
  40. data/spec/dummy/db/development.sqlite3 +0 -0
  41. data/spec/dummy/db/schema.rb +16 -0
  42. data/spec/dummy/db/test.sqlite3 +0 -0
  43. data/spec/dummy/log/test.log +3830 -0
  44. data/spec/dummy/public/404.html +67 -0
  45. data/spec/dummy/public/422.html +67 -0
  46. data/spec/dummy/public/500.html +66 -0
  47. data/spec/dummy/public/favicon.ico +0 -0
  48. data/spec/dummy/spec +1 -0
  49. data/spec/lib/chatops/controller_spec.rb +376 -0
  50. data/spec/rails_helper.rb +65 -0
  51. data/spec/spec_helper.rb +92 -0
  52. data/spec/support/json_response.rb +28 -0
  53. metadata +195 -0
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/404.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
@@ -0,0 +1 @@
1
+ ../../spec
@@ -0,0 +1,376 @@
1
+ require 'rails_helper'
2
+ require 'openssl'
3
+ require 'base64'
4
+
5
+ describe ActionController::Base, type: :controller do
6
+ controller do
7
+ include Chatops::Controller
8
+ chatops_namespace :test
9
+ chatops_help "Chatops of and relating to testing"
10
+ chatops_error_response "Try checking haystack?"
11
+
12
+ before_action :ensure_app_given, :only => [:wcid]
13
+
14
+ chatop :wcid,
15
+ /(?:where can i deploy|wcid)(?: (?<app>\S+))?/,
16
+ "where can i deploy?" do
17
+ return jsonrpc_invalid_params("I need nope, sorry") if params[:app] == "nope"
18
+ jsonrpc_success "You can deploy #{params["app"]} just fine."
19
+ end
20
+
21
+ chatop :foobar,
22
+ /(?:how can i foo and bar all at once)?/,
23
+ "how to foo and bar" do
24
+ raise "there's always params" unless jsonrpc_params.respond_to?(:[])
25
+ jsonrpc_success "You just foo and bar like it just don't matter"
26
+ end
27
+
28
+ skip_before_action :ensure_method_exists, only: :non_chatop_method
29
+ def non_chatop_method
30
+ render :plain => "Why would you have something thats not a chatop?"
31
+ end
32
+
33
+ def unexcluded_chatop_method
34
+ render :text => "Sadly, I'll never be reached"
35
+ end
36
+
37
+ def ensure_app_given
38
+ return jsonrpc_invalid_params("I need an app, every time") unless params[:app].present?
39
+ end
40
+ end
41
+
42
+ before :each do
43
+ routes.draw do
44
+ get "/_chatops" => "anonymous#list"
45
+ post "/_chatops/:chatop", controller: "anonymous", action: :execute_chatop
46
+ get "/other" => "anonymous#non_chatop_method"
47
+ get "/other_will_fail" => "anonymous#unexcluded_chatop_method"
48
+ end
49
+
50
+ @private_key = OpenSSL::PKey::RSA.new(2048)
51
+ ENV["CHATOPS_AUTH_PUBLIC_KEY"] = @private_key.public_key.to_pem
52
+ ENV["CHATOPS_AUTH_BASE_URL"] = "http://test.host"
53
+ end
54
+
55
+ def rails_flexible_post(path, outer_params, jsonrpc_params = nil)
56
+ if Rails.version.starts_with?("4")
57
+ post path, outer_params.merge("params" => jsonrpc_params)
58
+ else
59
+ jsonrpc_params ||= {}
60
+ post path, :params => outer_params.merge("params" => jsonrpc_params)
61
+ end
62
+ end
63
+
64
+ it "requires authentication" do
65
+ request.headers["Chatops-Timestamp"] = Time.now.utc.iso8601
66
+ get :list
67
+ expect(response.status).to eq 403
68
+ end
69
+
70
+ it "allows public key authentication for a GET request" do
71
+ nonce = SecureRandom.hex(20)
72
+ timestamp = Time.now.utc.iso8601
73
+ request.headers["Chatops-Nonce"] = nonce
74
+ request.headers["Chatops-Timestamp"] = timestamp
75
+ digest = OpenSSL::Digest::SHA256.new
76
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
77
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
78
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
79
+ get :list
80
+ expect(response.headers["Chatops-Signature-String"]).to eq Base64.strict_encode64(signature_string)
81
+ expect(response.status).to eq 200
82
+ expect(response).to be_valid_json
83
+ end
84
+
85
+ it "allows public key authentication for a POST request" do
86
+ nonce = SecureRandom.hex(20)
87
+ timestamp = Time.now.utc.iso8601
88
+ request.headers["Chatops-Nonce"] = nonce
89
+ request.headers["Chatops-Timestamp"] = timestamp
90
+ digest = OpenSSL::Digest::SHA256.new
91
+ params = { :room_id => "123", :user => "bhuga", :params => {}}
92
+
93
+ body = params.to_json
94
+ @request.headers["Content-Type"] = "application/json"
95
+ @request.env["RAW_POST_DATA"] = body
96
+ signature_string = "http://test.host/_chatops/foobar\n#{nonce}\n#{timestamp}\n#{body}"
97
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
98
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
99
+
100
+ major_version = Rails.version.split(".")[0].to_i
101
+ if major_version >= 5
102
+ post :execute_chatop, params: params.merge(chatop: "foobar")
103
+ else
104
+ post :execute_chatop, params.merge(chatop: "foobar")
105
+ end
106
+
107
+ expect(response.status).to eq 200
108
+ expect(response).to be_valid_json
109
+ end
110
+
111
+ it "allows using a second public key to authenticate" do
112
+ ENV["CHATOPS_AUTH_ALT_PUBLIC_KEY"] = ENV["CHATOPS_AUTH_PUBLIC_KEY"]
113
+ other_key = OpenSSL::PKey::RSA.new(2048)
114
+ ENV["CHATOPS_AUTH_PUBLIC_KEY"] = other_key.public_key.to_pem
115
+ nonce = SecureRandom.hex(20)
116
+ timestamp = Time.now.utc.iso8601
117
+ request.headers["Chatops-Nonce"] = nonce
118
+ request.headers["Chatops-Timestamp"] = timestamp
119
+ digest = OpenSSL::Digest::SHA256.new
120
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
121
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
122
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
123
+ get :list
124
+ expect(response.status).to eq 200
125
+ expect(response).to be_valid_json
126
+ end
127
+
128
+ it "raises an error trying to auth without a base url" do
129
+ nonce = SecureRandom.hex(20)
130
+ timestamp = Time.now.utc.iso8601
131
+ request.headers["Chatops-Nonce"] = nonce
132
+ request.headers["Chatops-Timestamp"] = timestamp
133
+ digest = OpenSSL::Digest::SHA256.new
134
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
135
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
136
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
137
+ ENV.delete "CHATOPS_AUTH_BASE_URL"
138
+ expect {
139
+ get :list
140
+ }.to raise_error(Chatops::Controller::ConfigurationError)
141
+ end
142
+
143
+ it "raises an error trying to auth without a public key" do
144
+ nonce = SecureRandom.hex(20)
145
+ timestamp = Time.now.utc.iso8601
146
+ request.headers["Chatops-Nonce"] = nonce
147
+ request.headers["Chatops-Timestamp"] = timestamp
148
+ digest = OpenSSL::Digest::SHA256.new
149
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
150
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
151
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
152
+ ENV.delete "CHATOPS_AUTH_PUBLIC_KEY"
153
+ expect {
154
+ get :list
155
+ }.to raise_error(Chatops::Controller::ConfigurationError)
156
+ end
157
+
158
+ it "doesn't authenticate with the wrong public key'" do
159
+ other_key = OpenSSL::PKey::RSA.new(2048)
160
+ ENV["CHATOPS_AUTH_PUBLIC_KEY"] = other_key.public_key.to_pem
161
+ nonce = SecureRandom.hex(20)
162
+ timestamp = Time.now.utc.iso8601
163
+ request.headers["Chatops-Nonce"] = nonce
164
+ request.headers["Chatops-Timestamp"] = timestamp
165
+ digest = OpenSSL::Digest::SHA256.new
166
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
167
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
168
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
169
+ get :list
170
+ expect(response.status).to eq 403
171
+ end
172
+
173
+ it "doesn't allow requests more than 1 minute old" do
174
+ nonce = SecureRandom.hex(20)
175
+ timestamp = 2.minutes.ago.utc.iso8601
176
+ request.headers["Chatops-Nonce"] = nonce
177
+ request.headers["Chatops-Timestamp"] = timestamp
178
+ digest = OpenSSL::Digest::SHA256.new
179
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
180
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
181
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
182
+ get :list
183
+ expect(response.status).to eq 403
184
+ expect(response.body).to include "Chatops timestamp not within 1 minute"
185
+ end
186
+
187
+ it "doesn't allow requests more than 1 minute in the future" do
188
+ nonce = SecureRandom.hex(20)
189
+ timestamp = 2.minutes.from_now.utc.iso8601
190
+ request.headers["Chatops-Nonce"] = nonce
191
+ request.headers["Chatops-Timestamp"] = timestamp
192
+ digest = OpenSSL::Digest::SHA256.new
193
+ signature_string = "http://test.host/_chatops\n#{nonce}\n#{timestamp}\n"
194
+ signature = Base64.encode64(@private_key.sign(digest, signature_string))
195
+ request.headers["Chatops-Signature"] = "Signature keyid=foo,signature=#{signature}"
196
+ get :list
197
+ expect(response.status).to eq 403
198
+ expect(response.body).to include "Chatops timestamp not within 1 minute"
199
+ end
200
+
201
+ it "does not add authentication to non-chatops routes" do
202
+ get :non_chatop_method
203
+ expect(response.status).to eq 200
204
+ expect(response.body).to eq "Why would you have something thats not a chatop?"
205
+ end
206
+
207
+ context "when authenticated" do
208
+ before do
209
+ chatops_auth!
210
+ end
211
+
212
+ it "provides a list method" do
213
+ get :list
214
+ expect(response.status).to eq 200
215
+ expect(json_response).to eq({
216
+ "namespace" => "test",
217
+ "help" => "Chatops of and relating to testing",
218
+ "error_response" => "Try checking haystack?",
219
+ "methods" => {
220
+ "wcid" => {
221
+ "help" => "where can i deploy?",
222
+ "regex" => /(?:where can i deploy|wcid)(?: (?<app>\S+))?/.source,
223
+ "params" => ["app"],
224
+ "path" => "wcid"
225
+ },
226
+ "foobar" => {
227
+ "help" => "how to foo and bar",
228
+ "regex" => /(?:how can i foo and bar all at once)?/.source,
229
+ "params" => [],
230
+ "path" => "foobar"
231
+ }
232
+ },
233
+ "version" => "3"
234
+ })
235
+ end
236
+
237
+ it "requires a user be sent to chatops" do
238
+ rails_flexible_post :execute_chatop, chatop: :foobar
239
+ expect(response.status).to eq 400
240
+ expect(json_response).to eq({
241
+ "jsonrpc" => "2.0",
242
+ "id" => nil,
243
+ "error" => {
244
+ "code" => -32602,
245
+ "message" => "A username must be supplied as 'user'"
246
+ }
247
+ })
248
+ end
249
+
250
+ it "returns method not found for a not found method" do
251
+ rails_flexible_post :execute_chatop, chatop: :barfoo, user: "foo"
252
+ expect(json_response).to eq({
253
+ "jsonrpc" => "2.0",
254
+ "id" => nil,
255
+ "error" => {
256
+ "code" => -32601,
257
+ "message" => "Method not found"
258
+ }
259
+ })
260
+ expect(response.status).to eq 404
261
+ end
262
+
263
+ it "requires skipping a before_action to find non-chatop methods, sorry about that" do
264
+ get :unexcluded_chatop_method
265
+ expect(json_response).to eq({
266
+ "jsonrpc" => "2.0",
267
+ "id" => nil,
268
+ "error" => {
269
+ "code" => -32601,
270
+ "message" => "Method not found"
271
+ }
272
+ })
273
+ expect(response.status).to eq 404
274
+ end
275
+
276
+ it "runs a known method" do
277
+ rails_flexible_post :execute_chatop, chatop: :foobar, user: "foo"
278
+ expect(json_response).to eq({
279
+ "jsonrpc" => "2.0",
280
+ "id" => nil,
281
+ "result" => "You just foo and bar like it just don't matter"
282
+ })
283
+ expect(response.status).to eq 200
284
+ end
285
+
286
+ it "passes parameters to methods" do
287
+ rails_flexible_post :execute_chatop, { :chatop => "wcid", :user => "foo" }, { "app" => "foo" }
288
+ expect(json_response).to eq({
289
+ "jsonrpc" => "2.0",
290
+ "id" => nil,
291
+ "result" => "You can deploy foo just fine."
292
+ })
293
+ expect(response.status).to eq 200
294
+ end
295
+
296
+ it "uses typical controller fun like before_action" do
297
+ rails_flexible_post :execute_chatop, :chatop => "wcid", :user => "foo"
298
+ expect(json_response).to eq({
299
+ "jsonrpc" => "2.0",
300
+ "id" => nil,
301
+ "error" => {
302
+ "code" => -32602,
303
+ "message" => "I need an app, every time"
304
+ }
305
+ })
306
+ expect(response.status).to eq 400
307
+ end
308
+
309
+ it "allows methods to return invalid params with a message" do
310
+ rails_flexible_post :execute_chatop, { :chatop => "wcid", :user => "foo" }, { "app" => "nope" }
311
+ expect(response.status).to eq 400
312
+ expect(json_response).to eq({
313
+ "jsonrpc" => "2.0",
314
+ "id" => nil,
315
+ "error" => {
316
+ "code" => -32602,
317
+ "message" => "I need nope, sorry"
318
+ }
319
+ })
320
+ end
321
+
322
+ context "rspec helpers" do
323
+ it "makes it easy to test a response" do
324
+ chatop "wcid", :user => "foo", :app => "foo"
325
+ expect(chatop_response).to eq "You can deploy foo just fine."
326
+ end
327
+
328
+ it "makes it easy to test an error message" do
329
+ chatop "wcid", :user => "foo", :app => "nope"
330
+ expect(chatop_error).to eq "I need nope, sorry"
331
+ end
332
+ end
333
+
334
+ context "regex-based test helpers" do
335
+ it "routes based on regexes from test helpers" do
336
+ chat "where can i deploy foobar", "bhuga"
337
+ expect(request.params["action"]).to eq "execute_chatop"
338
+ expect(request.params["chatop"]).to eq "wcid"
339
+ expect(request.params["user"]).to eq "bhuga"
340
+ expect(request.params["params"]["app"]).to eq "foobar"
341
+ expect(chatop_response).to eq "You can deploy foobar just fine."
342
+ end
343
+
344
+ it "works with generic arguments" do
345
+ chat "where can i deploy foobar --fruit apple --vegetable green celery", "bhuga"
346
+ expect(request.params["action"]).to eq "execute_chatop"
347
+ expect(request.params["chatop"]).to eq "wcid"
348
+ expect(request.params["user"]).to eq "bhuga"
349
+ expect(request.params["params"]["app"]).to eq "foobar"
350
+ expect(request.params["params"]["fruit"]).to eq "apple"
351
+ expect(request.params["params"]["vegetable"]).to eq "green celery"
352
+ expect(chatop_response).to eq "You can deploy foobar just fine."
353
+ end
354
+
355
+ it "works with boolean arguments" do
356
+ chat "where can i deploy foobar --this-is-sparta", "bhuga"
357
+ expect(request.params["action"]).to eq "execute_chatop"
358
+ expect(request.params["chatop"]).to eq "wcid"
359
+ expect(request.params["user"]).to eq "bhuga"
360
+ expect(request.params["params"]["this-is-sparta"]).to eq "true"
361
+ end
362
+
363
+ it "anchors regexes" do
364
+ expect {
365
+ chat "too bad that this message doesn't start with where can i deploy foobar", "bhuga"
366
+ }.to raise_error(Chatops::Controller::TestCaseHelpers::NoMatchingCommandRegex)
367
+ end
368
+
369
+ it "allows setting a v2 prefix" do
370
+ chatops_prefix "test-prefix"
371
+ chat "test-prefix where can i deploy foobar --this-is-sparta", "bhuga"
372
+ expect(request.params["chatop"]).to eq "wcid"
373
+ end
374
+ end
375
+ end
376
+ end