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.
- checksums.yaml +7 -0
- data/README.md +204 -0
- data/lib/chatops-controller.rb +1 -0
- data/lib/chatops.rb +21 -0
- data/lib/chatops/controller.rb +209 -0
- data/lib/chatops/controller/rspec.rb +5 -0
- data/lib/chatops/controller/test_case.rb +5 -0
- data/lib/chatops/controller/test_case_helpers.rb +91 -0
- data/lib/chatops/controller/version.rb +3 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +24 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +46 -0
- data/spec/dummy/config/initializers/assets.rb +13 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +16 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +3830 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/spec +1 -0
- data/spec/lib/chatops/controller_spec.rb +376 -0
- data/spec/rails_helper.rb +65 -0
- data/spec/spec_helper.rb +92 -0
- data/spec/support/json_response.rb +28 -0
- 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
|
data/spec/dummy/spec
ADDED
@@ -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
|