chatops-controller 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
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