sqs_web 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/sqs_web/application/public/javascripts/application.js +12 -2
- data/lib/sqs_web/application/views/dlq_console.erb +1 -1
- data/lib/sqs_web/application/views/message.erb +1 -1
- data/spec/integration/app_spec.rb +1 -360
- data/spec/integration/dlq_console_spec.rb +308 -0
- data/spec/integration/overview_spec.rb +36 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/fake_sqs.rb +1 -1
- data/spec/support/rails_app.rb +1 -1
- data/spec/support/shared_context.rb +54 -0
- data/sqs_web.gemspec +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1255501537a0297a7b1eda47890fc64bc4919b74
|
4
|
+
data.tar.gz: 9663fb87014c3efe614e7c30c532657fa60897ed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f61f3cb396aa0bff8b8e4dcaca1166c7625c16201fb092e7fae80c9e71ca51fffb8997ee7a7cfddb74f480ef638df4cf5060c3bd5f80cba76ae60adccd6b7503
|
7
|
+
data.tar.gz: 179b3470d93fc17143e5acba25e9d769f9ad73eb0b231095b045c22ebb2f0694f6b3fa789a024028af8fc7f67f81e94913a5f732118ece790305b45ca6e3c0b8
|
@@ -1,6 +1,4 @@
|
|
1
1
|
$(function() {
|
2
|
-
var poll_interval = 3;
|
3
|
-
|
4
2
|
var relatizer = function(){
|
5
3
|
var dt = $(this).text(), relatized = $.relatizeDate(this)
|
6
4
|
if ($(this).parents("a").length > 0 || $(this).is("a")) {
|
@@ -55,4 +53,16 @@ $(function() {
|
|
55
53
|
$("#bulk_action_submit input").click(function() {
|
56
54
|
$('#bulk_action_form').attr("action", $(this).attr("action"));
|
57
55
|
});
|
56
|
+
|
57
|
+
$(".remove_single").click(function(e) {
|
58
|
+
if (!confirm("Are you sure you want to remove the message?")){
|
59
|
+
e.preventDefault();
|
60
|
+
}
|
61
|
+
});
|
62
|
+
|
63
|
+
$(".remove_bulk").click(function(e) {
|
64
|
+
if (!confirm("Are you sure you want to remove the selected messages?")){
|
65
|
+
e.preventDefault();
|
66
|
+
}
|
67
|
+
});
|
58
68
|
})
|
@@ -10,7 +10,7 @@
|
|
10
10
|
<%= csrf_token_tag %>
|
11
11
|
Select/Unselect All <input type="checkbox" id="select_all" />
|
12
12
|
<div id="bulk_action_submit">
|
13
|
-
<input type="submit" value="Bulk Remove" action="<%= u("bulk_remove") %>"/>
|
13
|
+
<input class="remove_bulk" type="submit" value="Bulk Remove" action="<%= u("bulk_remove") %>"/>
|
14
14
|
<input type="submit" value="Bulk Move to Source Queue" action="<%= u("bulk_requeue") %>"/>
|
15
15
|
</div>
|
16
16
|
</form>
|
@@ -8,7 +8,7 @@
|
|
8
8
|
<div class="controls">
|
9
9
|
<form action="<%= u("remove/#{queue[:name]}/#{message.message_id}") %>" method="post">
|
10
10
|
<%= csrf_token_tag %>
|
11
|
-
<input type="submit" value="Remove" />
|
11
|
+
<input class="remove_single" type="submit" value="Remove" />
|
12
12
|
</form>
|
13
13
|
or
|
14
14
|
<form action="<%= u("requeue/#{queue[:name]}/#{message.message_id}") %>" method="post">
|
@@ -1,33 +1,4 @@
|
|
1
|
-
|
2
|
-
require 'support/fake_sqs'
|
3
|
-
|
4
|
-
Capybara.app = RailsApp
|
5
|
-
|
6
|
-
RSpec.describe "Mounted in Rails Application", :sqs do
|
7
|
-
|
8
|
-
SOURCE_QUEUE_NAME = "TestSourceQueue"
|
9
|
-
|
10
|
-
DLQ_QUEUE_NAME = "TestSourceQueueDLQ"
|
11
|
-
|
12
|
-
let(:sqs) { Aws::SQS::Client.new(region: "us-east-1", credentials: Aws::Credentials.new("fake", "fake")) }
|
13
|
-
|
14
|
-
let(:source_queue_url) { sqs.get_queue_url(queue_name: SOURCE_QUEUE_NAME).queue_url }
|
15
|
-
|
16
|
-
let(:dlq_queue_url) { sqs.get_queue_url(queue_name: DLQ_QUEUE_NAME).queue_url }
|
17
|
-
|
18
|
-
before do
|
19
|
-
sqs.config.endpoint = $fake_sqs.uri
|
20
|
-
[SOURCE_QUEUE_NAME, DLQ_QUEUE_NAME].each{|queue_name| sqs.create_queue(queue_name: queue_name)}
|
21
|
-
dlq_arn = sqs.get_queue_attributes(queue_url: dlq_queue_url).attributes.fetch("QueueArn")
|
22
|
-
#Set DLQ
|
23
|
-
sqs.set_queue_attributes(
|
24
|
-
queue_url: source_queue_url,
|
25
|
-
attributes: {
|
26
|
-
"RedrivePolicy" => "{\"deadLetterTargetArn\":\"#{dlq_arn}\",\"maxReceiveCount\":10}"
|
27
|
-
}
|
28
|
-
)
|
29
|
-
SqsWeb.options[:queues] = [SOURCE_QUEUE_NAME, DLQ_QUEUE_NAME]
|
30
|
-
end
|
1
|
+
RSpec.describe "General Application features", :sqs do
|
31
2
|
|
32
3
|
# basic smoke test all the tabs
|
33
4
|
%w(overview dlq_console).each do |tab|
|
@@ -36,334 +7,4 @@ RSpec.describe "Mounted in Rails Application", :sqs do
|
|
36
7
|
expect(page.status_code).to eq 200
|
37
8
|
end
|
38
9
|
end
|
39
|
-
|
40
|
-
describe "Overview page" do
|
41
|
-
it "will show Visible Messages" do
|
42
|
-
default_messages
|
43
|
-
|
44
|
-
visit "/sqs/overview"
|
45
|
-
|
46
|
-
match_content(page, "#{SOURCE_QUEUE_NAME} 5 0 N/A")
|
47
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 3 0 #{source_queue_url}")
|
48
|
-
end
|
49
|
-
|
50
|
-
specify "In Flight Messages" do
|
51
|
-
default_messages
|
52
|
-
|
53
|
-
receive_messages(source_queue_url, {count: 3})
|
54
|
-
receive_messages(dlq_queue_url, {count: 2})
|
55
|
-
|
56
|
-
visit "/sqs/overview"
|
57
|
-
|
58
|
-
match_content(page, "#{SOURCE_QUEUE_NAME} 2 3 N/A")
|
59
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 1 2 #{source_queue_url}")
|
60
|
-
end
|
61
|
-
|
62
|
-
specify "should be default page" do
|
63
|
-
visit "/sqs"
|
64
|
-
|
65
|
-
expect(current_path).to eq "/sqs/overview"
|
66
|
-
end
|
67
|
-
|
68
|
-
specify "handle non existent queues" do
|
69
|
-
SqsWeb.options[:queues] = ["BOGUSQUEUE"]
|
70
|
-
|
71
|
-
visit "/sqs/overview"
|
72
|
-
|
73
|
-
match_content(page, "Aws::SQS::Errors::NonExistentQueue: BOGUSQUEUE")
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
describe "DLQ Console", js: true do
|
78
|
-
|
79
|
-
it "should only show unique entries for each message" do
|
80
|
-
message_ids = generate_messages(dlq_queue_url, 5).map{|c| c.message_id}
|
81
|
-
|
82
|
-
visit "/sqs/dlq_console"
|
83
|
-
|
84
|
-
message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 1}
|
85
|
-
end
|
86
|
-
|
87
|
-
it "should delete single message" do
|
88
|
-
messages = generate_messages(dlq_queue_url, 2)
|
89
|
-
deleted_message_id = messages.pop.message_id
|
90
|
-
retained_message_id = messages.pop.message_id
|
91
|
-
|
92
|
-
visit "/sqs/dlq_console"
|
93
|
-
|
94
|
-
first("#message_#{deleted_message_id}").hover
|
95
|
-
|
96
|
-
within("#message_#{deleted_message_id}") do
|
97
|
-
click_on "Remove"
|
98
|
-
end
|
99
|
-
|
100
|
-
success_message = "Message ID: #{deleted_message_id} in Queue #{DLQ_QUEUE_NAME} was successfully removed."
|
101
|
-
expect(first("#alert").text).to eq success_message
|
102
|
-
|
103
|
-
expect(page.all("#message_#{deleted_message_id}").count).to eq 0
|
104
|
-
expect(page.all("#message_#{retained_message_id}").count).to eq 1
|
105
|
-
|
106
|
-
visit "/sqs/overview"
|
107
|
-
|
108
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 1 0 #{source_queue_url}")
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should handle deleting single message that is already deleted" do
|
112
|
-
deleted_message_id = generate_messages(dlq_queue_url, 1).first.message_id
|
113
|
-
|
114
|
-
visit "/sqs/dlq_console"
|
115
|
-
|
116
|
-
sqs.purge_queue({ queue_url: dlq_queue_url })
|
117
|
-
|
118
|
-
first("#message_#{deleted_message_id}").hover
|
119
|
-
|
120
|
-
within("#message_#{deleted_message_id}") do
|
121
|
-
click_on "Remove"
|
122
|
-
end
|
123
|
-
|
124
|
-
error_message = "Message ID: #{deleted_message_id} in Queue #{DLQ_QUEUE_NAME} has already been deleted or is not visible."
|
125
|
-
expect(first("#alert").text).to eq error_message
|
126
|
-
end
|
127
|
-
|
128
|
-
it "should remove multiple selected messages" do
|
129
|
-
messages = generate_messages(dlq_queue_url, 6)
|
130
|
-
deleted_message_ids = messages.pop(4).map{|c| c.message_id}
|
131
|
-
retained_message_ids = messages.pop(2).map{|c| c.message_id}
|
132
|
-
|
133
|
-
visit "/sqs/dlq_console"
|
134
|
-
|
135
|
-
deleted_message_ids.each do |message_id|
|
136
|
-
first("#batch_action_item_#{message_id}").set(true)
|
137
|
-
end
|
138
|
-
|
139
|
-
click_on "Bulk Remove"
|
140
|
-
|
141
|
-
expect(first("#alert").text).to eq "Selected messages have been removed successfully."
|
142
|
-
|
143
|
-
deleted_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 0}
|
144
|
-
retained_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 1}
|
145
|
-
|
146
|
-
visit "/sqs/overview"
|
147
|
-
|
148
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 2 0 #{source_queue_url}")
|
149
|
-
end
|
150
|
-
|
151
|
-
it "should handle removing multiple selected messages where one or more is already deleted or not visible" do
|
152
|
-
generate_messages(dlq_queue_url, 3)
|
153
|
-
|
154
|
-
visit "/sqs/dlq_console"
|
155
|
-
|
156
|
-
messages = receive_messages(dlq_queue_url, {count: 3}).messages
|
157
|
-
sqs.delete_message({queue_url: dlq_queue_url, receipt_handle: messages[2].receipt_handle})
|
158
|
-
sqs.change_message_visibility_batch({
|
159
|
-
queue_url: dlq_queue_url,
|
160
|
-
entries: messages.take(2).map do |message|
|
161
|
-
{id: message.message_id, receipt_handle: message.receipt_handle, visibility_timeout: 0}
|
162
|
-
end
|
163
|
-
})
|
164
|
-
messages.each do |message|
|
165
|
-
first("#batch_action_item_#{message.message_id}").set(true)
|
166
|
-
end
|
167
|
-
|
168
|
-
click_on "Bulk Remove"
|
169
|
-
|
170
|
-
expect(first("#alert").text).to eq "One or more messages may have already been removed or is not visible."
|
171
|
-
|
172
|
-
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 0}
|
173
|
-
|
174
|
-
visit "/sqs/overview"
|
175
|
-
|
176
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 0 0 #{source_queue_url}")
|
177
|
-
end
|
178
|
-
|
179
|
-
it "should handle clicking on Bulk Remove without any selection" do
|
180
|
-
messages = generate_messages(dlq_queue_url, 3)
|
181
|
-
|
182
|
-
visit "/sqs/dlq_console"
|
183
|
-
|
184
|
-
click_on "Bulk Remove"
|
185
|
-
|
186
|
-
expect(first("#alert").text).to eq ""
|
187
|
-
|
188
|
-
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 1}
|
189
|
-
end
|
190
|
-
|
191
|
-
it "should render all information related to the visible messages" do
|
192
|
-
generate_messages(dlq_queue_url, 1)
|
193
|
-
|
194
|
-
visit "/sqs/dlq_console"
|
195
|
-
|
196
|
-
message = receive_messages(dlq_queue_url).messages.first
|
197
|
-
message.attributes["ApproximateReceiveCount"] = "1"
|
198
|
-
|
199
|
-
message_metadata = <<-EOF
|
200
|
-
ID #{message.message_id} or Receive Count 1
|
201
|
-
Queue Name #{DLQ_QUEUE_NAME} Origin Queue #{source_queue_url}
|
202
|
-
Message Body Test_0
|
203
|
-
EOF
|
204
|
-
|
205
|
-
message_entry = first("#message_#{message.message_id}")
|
206
|
-
|
207
|
-
within(message_entry) do
|
208
|
-
click_on "Toggle full message"
|
209
|
-
first(".toggle_format").click
|
210
|
-
end
|
211
|
-
|
212
|
-
match_content(message_entry, normalize_whitespace(message_metadata))
|
213
|
-
match_content(message_entry, normalize_whitespace(message.inspect.to_yaml.split('receipt_handle')[0]))
|
214
|
-
match_content(message_entry, normalize_whitespace(message.inspect.to_yaml.split('md5', 2)[1]))
|
215
|
-
match_content(message_entry, normalize_whitespace("Enqueued At #{Time.at(message.attributes["SentTimestamp"].to_i/1000).rfc822}"))
|
216
|
-
end
|
217
|
-
|
218
|
-
it "should not display any messages that are not in a DLQ" do
|
219
|
-
generate_messages(source_queue_url, 1)
|
220
|
-
|
221
|
-
visit "/sqs/dlq_console"
|
222
|
-
|
223
|
-
message = receive_messages(source_queue_url).messages.first
|
224
|
-
|
225
|
-
expect(first("#message_#{message.message_id}")).to be_nil
|
226
|
-
|
227
|
-
match_content(page, "Showing 0 visible messages")
|
228
|
-
end
|
229
|
-
|
230
|
-
it "should be able to move a single message to source queue" do
|
231
|
-
message_id = generate_messages(dlq_queue_url, 1).first.message_id
|
232
|
-
|
233
|
-
|
234
|
-
visit "/sqs/dlq_console"
|
235
|
-
|
236
|
-
first("#message_#{message_id}").hover
|
237
|
-
|
238
|
-
within("#message_#{message_id}") do
|
239
|
-
click_on "Move to Source Queue"
|
240
|
-
end
|
241
|
-
|
242
|
-
success_message = "Message ID: #{message_id} in Queue #{DLQ_QUEUE_NAME} was successfully moved to Source Queue #{source_queue_url}."
|
243
|
-
expect(first("#alert").text).to eq success_message
|
244
|
-
expect(page.all("#message_#{message_id}").count).to eq 0
|
245
|
-
|
246
|
-
visit "/sqs/overview"
|
247
|
-
|
248
|
-
match_content(page, "#{SOURCE_QUEUE_NAME} 1 0 N/A")
|
249
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 0 0 #{source_queue_url}")
|
250
|
-
|
251
|
-
moved_message = receive_messages(source_queue_url).messages.first
|
252
|
-
expect(moved_message).to_not be_nil
|
253
|
-
expect(moved_message.body).to eq "Test_0"
|
254
|
-
expect(moved_message.attributes["ApproximateReceiveCount"]).to eq "1"
|
255
|
-
expect(moved_message.message_attributes["foo_class"].to_hash).to eq({string_value: "FooWorker", data_type: "String"})
|
256
|
-
end
|
257
|
-
|
258
|
-
it "should move multiple selected messages" do
|
259
|
-
messages = generate_messages(dlq_queue_url, 6)
|
260
|
-
retained_message_ids = messages.pop(2).map{|c| c.message_id}
|
261
|
-
moved_message_ids = messages.pop(4).map{|c| c.message_id}
|
262
|
-
|
263
|
-
visit "/sqs/dlq_console"
|
264
|
-
|
265
|
-
moved_message_ids.each do |message_id|
|
266
|
-
first("#batch_action_item_#{message_id}").set(true)
|
267
|
-
end
|
268
|
-
|
269
|
-
click_on "Bulk Move to Source Queue"
|
270
|
-
|
271
|
-
expect(first("#alert").text).to eq "Selected messages have been requeued successfully."
|
272
|
-
|
273
|
-
moved_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 0}
|
274
|
-
retained_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 1}
|
275
|
-
|
276
|
-
visit "/sqs/overview"
|
277
|
-
|
278
|
-
match_content(page, "#{SOURCE_QUEUE_NAME} 4 0 N/A")
|
279
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 2 0 #{source_queue_url}")
|
280
|
-
|
281
|
-
moved_messages = receive_messages(source_queue_url, {count: 4}).messages.sort_by{|c| c.body}
|
282
|
-
moved_messages.each_with_index do |moved_message, index|
|
283
|
-
expect(moved_message).to_not be_nil
|
284
|
-
expect(moved_message.body).to match "Test_#{index}"
|
285
|
-
expect(moved_message.attributes["ApproximateReceiveCount"]).to eq "1"
|
286
|
-
expect(moved_message.message_attributes["foo_class"].to_hash).to eq({string_value: "FooWorker", data_type: "String"})
|
287
|
-
end
|
288
|
-
end
|
289
|
-
|
290
|
-
it "should handle moving multiple selected messages where one or more is already deleted or not visible" do
|
291
|
-
generate_messages(dlq_queue_url, 3)
|
292
|
-
|
293
|
-
visit "/sqs/dlq_console"
|
294
|
-
|
295
|
-
messages = receive_messages(dlq_queue_url, {count: 3}).messages
|
296
|
-
sqs.delete_message({queue_url: dlq_queue_url, receipt_handle: messages[2].receipt_handle})
|
297
|
-
sqs.change_message_visibility_batch({
|
298
|
-
queue_url: dlq_queue_url,
|
299
|
-
entries: messages.take(2).map do |message|
|
300
|
-
{id: message.message_id, receipt_handle: message.receipt_handle, visibility_timeout: 0}
|
301
|
-
end
|
302
|
-
})
|
303
|
-
messages.each do |message|
|
304
|
-
first("#batch_action_item_#{message.message_id}").set(true)
|
305
|
-
end
|
306
|
-
|
307
|
-
click_on "Bulk Move to Source Queue"
|
308
|
-
|
309
|
-
expect(first("#alert").text).to eq "One or more messages may have already been requeued or is not visible."
|
310
|
-
|
311
|
-
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 0}
|
312
|
-
|
313
|
-
visit "/sqs/overview"
|
314
|
-
|
315
|
-
match_content(page, "#{SOURCE_QUEUE_NAME} 2 0 N/A")
|
316
|
-
match_content(page, "#{DLQ_QUEUE_NAME} 0 0 #{source_queue_url}")
|
317
|
-
end
|
318
|
-
|
319
|
-
it "should handle clicking on Bulk Move to Source Queue without any selection" do
|
320
|
-
messages = generate_messages(dlq_queue_url, 3)
|
321
|
-
|
322
|
-
visit "/sqs/dlq_console"
|
323
|
-
|
324
|
-
click_on "Bulk Move to Source Queue"
|
325
|
-
|
326
|
-
expect(first("#alert").text).to eq ""
|
327
|
-
|
328
|
-
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 1}
|
329
|
-
end
|
330
|
-
|
331
|
-
it "should have a select/unselect all function" do
|
332
|
-
messages = generate_messages(dlq_queue_url, 3)
|
333
|
-
|
334
|
-
visit "/sqs/dlq_console"
|
335
|
-
|
336
|
-
first("#select_all").click
|
337
|
-
|
338
|
-
page.all(".bulk_check").each{|node| expect(node["checked"]).to eq true}
|
339
|
-
|
340
|
-
first("#select_all").click
|
341
|
-
|
342
|
-
page.all(".bulk_check").each{|node| expect(node["checked"]).to eq false}
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
def receive_messages(queue_url, options = {count: 1})
|
347
|
-
sqs.receive_message({
|
348
|
-
queue_url: queue_url,
|
349
|
-
attribute_names: ["All"],
|
350
|
-
message_attribute_names: ["All"],
|
351
|
-
max_number_of_messages: options[:count],
|
352
|
-
wait_time_seconds: 1,
|
353
|
-
visibility_timeout: options[:visibility_timeout]
|
354
|
-
})
|
355
|
-
end
|
356
|
-
|
357
|
-
def default_messages
|
358
|
-
generate_messages(source_queue_url, 5) + generate_messages(dlq_queue_url, 3)
|
359
|
-
end
|
360
|
-
|
361
|
-
def generate_messages(queue_url, count=1)
|
362
|
-
messages = []
|
363
|
-
count.times do |time|
|
364
|
-
messages << sqs.send_message(queue_url: queue_url, message_body: "Test_#{time}",
|
365
|
-
message_attributes: {"foo_class"=> {string_value: "FooWorker", data_type: "String"}})
|
366
|
-
end
|
367
|
-
messages
|
368
|
-
end
|
369
10
|
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
RSpec.describe "DLQ Console", js: true, sqs: true do
|
2
|
+
|
3
|
+
it "should only show unique entries for each message" do
|
4
|
+
message_ids = generate_messages(dlq_queue_url, 5).map{|c| c.message_id}
|
5
|
+
|
6
|
+
visit "/sqs/dlq_console"
|
7
|
+
|
8
|
+
message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 1}
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should render all information related to the visible messages" do
|
12
|
+
generate_messages(dlq_queue_url, 1)
|
13
|
+
|
14
|
+
visit "/sqs/dlq_console"
|
15
|
+
|
16
|
+
message = receive_messages(dlq_queue_url).messages.first
|
17
|
+
message.attributes["ApproximateReceiveCount"] = "1"
|
18
|
+
|
19
|
+
message_metadata = <<-EOF
|
20
|
+
ID #{message.message_id} or Receive Count 1
|
21
|
+
Queue Name #{DLQ_QUEUE_NAME} Origin Queue #{source_queue_url}
|
22
|
+
Message Body Test_0
|
23
|
+
EOF
|
24
|
+
|
25
|
+
message_entry = first("#message_#{message.message_id}")
|
26
|
+
|
27
|
+
within(message_entry) do
|
28
|
+
click_on "Toggle full message"
|
29
|
+
first(".toggle_format").click
|
30
|
+
end
|
31
|
+
|
32
|
+
match_content(message_entry, normalize_whitespace(message_metadata))
|
33
|
+
match_content(message_entry, normalize_whitespace(message.inspect.to_yaml.split('receipt_handle')[0]))
|
34
|
+
match_content(message_entry, normalize_whitespace(message.inspect.to_yaml.split('md5', 2)[1]))
|
35
|
+
match_content(message_entry, normalize_whitespace("Enqueued At #{Time.at(message.attributes["SentTimestamp"].to_i/1000).rfc822}"))
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not display any messages that are not in a DLQ" do
|
39
|
+
generate_messages(source_queue_url, 1)
|
40
|
+
|
41
|
+
visit "/sqs/dlq_console"
|
42
|
+
|
43
|
+
message = receive_messages(source_queue_url).messages.first
|
44
|
+
|
45
|
+
expect(first("#message_#{message.message_id}")).to be_nil
|
46
|
+
|
47
|
+
match_content(page, "Showing 0 visible messages")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have a select/unselect all function" do
|
51
|
+
messages = generate_messages(dlq_queue_url, 3)
|
52
|
+
|
53
|
+
visit "/sqs/dlq_console"
|
54
|
+
|
55
|
+
first("#select_all").click
|
56
|
+
|
57
|
+
page.all(".bulk_check").each{|node| expect(node["checked"]).to eq true}
|
58
|
+
|
59
|
+
first("#select_all").click
|
60
|
+
|
61
|
+
page.all(".bulk_check").each{|node| expect(node["checked"]).to eq false}
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "Remove" do
|
65
|
+
it "should delete single message" do
|
66
|
+
messages = generate_messages(dlq_queue_url, 2)
|
67
|
+
deleted_message_id = messages.pop.message_id
|
68
|
+
retained_message_id = messages.pop.message_id
|
69
|
+
|
70
|
+
visit "/sqs/dlq_console"
|
71
|
+
|
72
|
+
first("#message_#{deleted_message_id}").hover
|
73
|
+
|
74
|
+
within("#message_#{deleted_message_id}") do
|
75
|
+
click_on "Remove"
|
76
|
+
end
|
77
|
+
|
78
|
+
success_message = "Message ID: #{deleted_message_id} in Queue #{DLQ_QUEUE_NAME} was successfully removed."
|
79
|
+
expect(first("#alert").text).to eq success_message
|
80
|
+
|
81
|
+
expect(page.all("#message_#{deleted_message_id}").count).to eq 0
|
82
|
+
expect(page.all("#message_#{retained_message_id}").count).to eq 1
|
83
|
+
|
84
|
+
visit "/sqs/overview"
|
85
|
+
|
86
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 1 0 #{source_queue_url}")
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should show a confirmation popup when deleting single message" do
|
90
|
+
messages = generate_messages(dlq_queue_url, 2)
|
91
|
+
deleted_message_id = messages.pop.message_id
|
92
|
+
|
93
|
+
visit "/sqs/dlq_console"
|
94
|
+
|
95
|
+
first("#message_#{deleted_message_id}").hover
|
96
|
+
|
97
|
+
message = page.accept_confirm do
|
98
|
+
within("#message_#{deleted_message_id}") do
|
99
|
+
click_on "Remove"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
expect(message).to eq('Are you sure you want to remove the message?')
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should handle deleting single message that is already deleted" do
|
107
|
+
deleted_message_id = generate_messages(dlq_queue_url, 1).first.message_id
|
108
|
+
|
109
|
+
visit "/sqs/dlq_console"
|
110
|
+
|
111
|
+
sqs.purge_queue({ queue_url: dlq_queue_url })
|
112
|
+
|
113
|
+
first("#message_#{deleted_message_id}").hover
|
114
|
+
|
115
|
+
within("#message_#{deleted_message_id}") do
|
116
|
+
click_on "Remove"
|
117
|
+
end
|
118
|
+
|
119
|
+
error_message = "Message ID: #{deleted_message_id} in Queue #{DLQ_QUEUE_NAME} has already been deleted or is not visible."
|
120
|
+
expect(first("#alert").text).to eq error_message
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "Bulk Remove" do
|
125
|
+
it "should remove multiple selected messages" do
|
126
|
+
messages = generate_messages(dlq_queue_url, 6)
|
127
|
+
deleted_message_ids = messages.pop(4).map{|c| c.message_id}
|
128
|
+
retained_message_ids = messages.pop(2).map{|c| c.message_id}
|
129
|
+
|
130
|
+
visit "/sqs/dlq_console"
|
131
|
+
|
132
|
+
deleted_message_ids.each do |message_id|
|
133
|
+
first("#batch_action_item_#{message_id}").set(true)
|
134
|
+
end
|
135
|
+
|
136
|
+
click_on "Bulk Remove"
|
137
|
+
|
138
|
+
expect(first("#alert").text).to eq "Selected messages have been removed successfully."
|
139
|
+
|
140
|
+
deleted_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 0}
|
141
|
+
retained_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 1}
|
142
|
+
|
143
|
+
visit "/sqs/overview"
|
144
|
+
|
145
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 2 0 #{source_queue_url}")
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should show a confirmation popup when removing multiple messages" do
|
149
|
+
messages = generate_messages(dlq_queue_url, 6)
|
150
|
+
deleted_message_ids = messages.pop(4).map{|c| c.message_id}
|
151
|
+
|
152
|
+
visit "/sqs/dlq_console"
|
153
|
+
|
154
|
+
deleted_message_ids.each do |message_id|
|
155
|
+
first("#batch_action_item_#{message_id}").set(true)
|
156
|
+
end
|
157
|
+
|
158
|
+
message = page.accept_confirm do
|
159
|
+
click_on "Bulk Remove"
|
160
|
+
end
|
161
|
+
|
162
|
+
expect(message).to eq('Are you sure you want to remove the selected messages?')
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should handle removing multiple selected messages where one or more is already deleted or not visible" do
|
166
|
+
generate_messages(dlq_queue_url, 3)
|
167
|
+
|
168
|
+
visit "/sqs/dlq_console"
|
169
|
+
|
170
|
+
messages = receive_messages(dlq_queue_url, {count: 3}).messages
|
171
|
+
sqs.delete_message({queue_url: dlq_queue_url, receipt_handle: messages[2].receipt_handle})
|
172
|
+
sqs.change_message_visibility_batch({
|
173
|
+
queue_url: dlq_queue_url,
|
174
|
+
entries: messages.take(2).map do |message|
|
175
|
+
{id: message.message_id, receipt_handle: message.receipt_handle, visibility_timeout: 0}
|
176
|
+
end
|
177
|
+
})
|
178
|
+
messages.each do |message|
|
179
|
+
first("#batch_action_item_#{message.message_id}").set(true)
|
180
|
+
end
|
181
|
+
|
182
|
+
click_on "Bulk Remove"
|
183
|
+
|
184
|
+
expect(first("#alert").text).to eq "One or more messages may have already been removed or is not visible."
|
185
|
+
|
186
|
+
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 0}
|
187
|
+
|
188
|
+
visit "/sqs/overview"
|
189
|
+
|
190
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 0 0 #{source_queue_url}")
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should handle clicking on Bulk Remove without any selection" do
|
194
|
+
messages = generate_messages(dlq_queue_url, 3)
|
195
|
+
|
196
|
+
visit "/sqs/dlq_console"
|
197
|
+
|
198
|
+
click_on "Bulk Remove"
|
199
|
+
|
200
|
+
expect(first("#alert").text).to eq ""
|
201
|
+
|
202
|
+
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 1}
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "Move to Source Queue should be able to move a single message to source queue" do
|
207
|
+
message_id = generate_messages(dlq_queue_url, 1).first.message_id
|
208
|
+
|
209
|
+
|
210
|
+
visit "/sqs/dlq_console"
|
211
|
+
|
212
|
+
first("#message_#{message_id}").hover
|
213
|
+
|
214
|
+
within("#message_#{message_id}") do
|
215
|
+
click_on "Move to Source Queue"
|
216
|
+
end
|
217
|
+
|
218
|
+
success_message = "Message ID: #{message_id} in Queue #{DLQ_QUEUE_NAME} was successfully moved to Source Queue #{source_queue_url}."
|
219
|
+
expect(first("#alert").text).to eq success_message
|
220
|
+
expect(page.all("#message_#{message_id}").count).to eq 0
|
221
|
+
|
222
|
+
visit "/sqs/overview"
|
223
|
+
|
224
|
+
match_content(page, "#{SOURCE_QUEUE_NAME} 1 0 N/A")
|
225
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 0 0 #{source_queue_url}")
|
226
|
+
|
227
|
+
moved_message = receive_messages(source_queue_url).messages.first
|
228
|
+
expect(moved_message).to_not be_nil
|
229
|
+
expect(moved_message.body).to eq "Test_0"
|
230
|
+
expect(moved_message.attributes["ApproximateReceiveCount"]).to eq "1"
|
231
|
+
expect(moved_message.message_attributes["foo_class"].to_hash).to eq({string_value: "FooWorker", data_type: "String"})
|
232
|
+
end
|
233
|
+
|
234
|
+
describe "Bulk Move to Source Queue" do
|
235
|
+
it "should move multiple selected messages" do
|
236
|
+
messages = generate_messages(dlq_queue_url, 6)
|
237
|
+
retained_message_ids = messages.pop(2).map{|c| c.message_id}
|
238
|
+
moved_message_ids = messages.pop(4).map{|c| c.message_id}
|
239
|
+
|
240
|
+
visit "/sqs/dlq_console"
|
241
|
+
|
242
|
+
moved_message_ids.each do |message_id|
|
243
|
+
first("#batch_action_item_#{message_id}").set(true)
|
244
|
+
end
|
245
|
+
|
246
|
+
click_on "Bulk Move to Source Queue"
|
247
|
+
|
248
|
+
expect(first("#alert").text).to eq "Selected messages have been requeued successfully."
|
249
|
+
|
250
|
+
moved_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 0}
|
251
|
+
retained_message_ids.each{|message_id| expect(page.all("#message_#{message_id}").count).to eq 1}
|
252
|
+
|
253
|
+
visit "/sqs/overview"
|
254
|
+
|
255
|
+
match_content(page, "#{SOURCE_QUEUE_NAME} 4 0 N/A")
|
256
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 2 0 #{source_queue_url}")
|
257
|
+
|
258
|
+
moved_messages = receive_messages(source_queue_url, {count: 4}).messages.sort_by{|c| c.body}
|
259
|
+
moved_messages.each_with_index do |moved_message, index|
|
260
|
+
expect(moved_message).to_not be_nil
|
261
|
+
expect(moved_message.body).to match "Test_#{index}"
|
262
|
+
expect(moved_message.attributes["ApproximateReceiveCount"]).to eq "1"
|
263
|
+
expect(moved_message.message_attributes["foo_class"].to_hash).to eq({string_value: "FooWorker", data_type: "String"})
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should handle moving multiple selected messages where one or more is already deleted or not visible" do
|
268
|
+
generate_messages(dlq_queue_url, 3)
|
269
|
+
|
270
|
+
visit "/sqs/dlq_console"
|
271
|
+
|
272
|
+
messages = receive_messages(dlq_queue_url, {count: 3}).messages
|
273
|
+
sqs.delete_message({queue_url: dlq_queue_url, receipt_handle: messages[2].receipt_handle})
|
274
|
+
sqs.change_message_visibility_batch({
|
275
|
+
queue_url: dlq_queue_url,
|
276
|
+
entries: messages.take(2).map do |message|
|
277
|
+
{id: message.message_id, receipt_handle: message.receipt_handle, visibility_timeout: 0}
|
278
|
+
end
|
279
|
+
})
|
280
|
+
messages.each do |message|
|
281
|
+
first("#batch_action_item_#{message.message_id}").set(true)
|
282
|
+
end
|
283
|
+
|
284
|
+
click_on "Bulk Move to Source Queue"
|
285
|
+
|
286
|
+
expect(first("#alert").text).to eq "One or more messages may have already been requeued or is not visible."
|
287
|
+
|
288
|
+
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 0}
|
289
|
+
|
290
|
+
visit "/sqs/overview"
|
291
|
+
|
292
|
+
match_content(page, "#{SOURCE_QUEUE_NAME} 2 0 N/A")
|
293
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 0 0 #{source_queue_url}")
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should handle clicking on Bulk Move to Source Queue without any selection" do
|
297
|
+
messages = generate_messages(dlq_queue_url, 3)
|
298
|
+
|
299
|
+
visit "/sqs/dlq_console"
|
300
|
+
|
301
|
+
click_on "Bulk Move to Source Queue"
|
302
|
+
|
303
|
+
expect(first("#alert").text).to eq ""
|
304
|
+
|
305
|
+
messages.each{|message| expect(page.all("#message_#{message.message_id}").count).to eq 1}
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
RSpec.describe "Overview Page", :sqs do
|
2
|
+
it "will show Visible Messages" do
|
3
|
+
default_messages
|
4
|
+
|
5
|
+
visit "/sqs/overview"
|
6
|
+
|
7
|
+
match_content(page, "#{SOURCE_QUEUE_NAME} 5 0 N/A")
|
8
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 3 0 #{source_queue_url}")
|
9
|
+
end
|
10
|
+
|
11
|
+
it "will show In Flight Messages" do
|
12
|
+
default_messages
|
13
|
+
|
14
|
+
receive_messages(source_queue_url, {count: 3})
|
15
|
+
receive_messages(dlq_queue_url, {count: 2})
|
16
|
+
|
17
|
+
visit "/sqs/overview"
|
18
|
+
|
19
|
+
match_content(page, "#{SOURCE_QUEUE_NAME} 2 3 N/A")
|
20
|
+
match_content(page, "#{DLQ_QUEUE_NAME} 1 2 #{source_queue_url}")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should be default page" do
|
24
|
+
visit "/sqs"
|
25
|
+
|
26
|
+
expect(current_path).to eq "/sqs/overview"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should gracefully handle non existent queues" do
|
30
|
+
SqsWeb.options[:queues] = ["BOGUSQUEUE"]
|
31
|
+
|
32
|
+
visit "/sqs/overview"
|
33
|
+
|
34
|
+
match_content(page, "Aws::SQS::Errors::NonExistentQueue: BOGUSQUEUE")
|
35
|
+
end
|
36
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/fake_sqs.rb
CHANGED
@@ -13,7 +13,7 @@ SqsWeb.options[:aws][:secret_access_key] = "fake"
|
|
13
13
|
SqsWeb.options[:aws][:endpoint] = $fake_sqs.uri
|
14
14
|
|
15
15
|
RSpec.configure do |config|
|
16
|
-
config.before(:
|
16
|
+
config.before(:suite) { $fake_sqs.start }
|
17
17
|
config.before(:each, :sqs) { $fake_sqs.reset }
|
18
18
|
config.after(:suite) { $fake_sqs.stop }
|
19
19
|
end
|
data/spec/support/rails_app.rb
CHANGED
@@ -0,0 +1,54 @@
|
|
1
|
+
SOURCE_QUEUE_NAME = "TestSourceQueue"
|
2
|
+
|
3
|
+
DLQ_QUEUE_NAME = "TestSourceQueueDLQ"
|
4
|
+
|
5
|
+
RSpec.shared_context "sqs_setup", :sqs do
|
6
|
+
require 'support/rails_app'
|
7
|
+
require 'support/fake_sqs'
|
8
|
+
|
9
|
+
Capybara.app = RailsApp
|
10
|
+
|
11
|
+
let(:sqs) { Aws::SQS::Client.new(region: "us-east-1", credentials: Aws::Credentials.new("fake", "fake")) }
|
12
|
+
|
13
|
+
let(:source_queue_url) { sqs.get_queue_url(queue_name: SOURCE_QUEUE_NAME).queue_url }
|
14
|
+
|
15
|
+
let(:dlq_queue_url) { sqs.get_queue_url(queue_name: DLQ_QUEUE_NAME).queue_url }
|
16
|
+
|
17
|
+
before do
|
18
|
+
sqs.config.endpoint = $fake_sqs.uri
|
19
|
+
[SOURCE_QUEUE_NAME, DLQ_QUEUE_NAME].each{|queue_name| sqs.create_queue(queue_name: queue_name)}
|
20
|
+
dlq_arn = sqs.get_queue_attributes(queue_url: dlq_queue_url).attributes.fetch("QueueArn")
|
21
|
+
#Set DLQ
|
22
|
+
sqs.set_queue_attributes(
|
23
|
+
queue_url: source_queue_url,
|
24
|
+
attributes: {
|
25
|
+
"RedrivePolicy" => "{\"deadLetterTargetArn\":\"#{dlq_arn}\",\"maxReceiveCount\":10}"
|
26
|
+
}
|
27
|
+
)
|
28
|
+
SqsWeb.options[:queues] = [SOURCE_QUEUE_NAME, DLQ_QUEUE_NAME]
|
29
|
+
end
|
30
|
+
|
31
|
+
def receive_messages(queue_url, options = {count: 1})
|
32
|
+
sqs.receive_message({
|
33
|
+
queue_url: queue_url,
|
34
|
+
attribute_names: ["All"],
|
35
|
+
message_attribute_names: ["All"],
|
36
|
+
max_number_of_messages: options[:count],
|
37
|
+
wait_time_seconds: 1,
|
38
|
+
visibility_timeout: options[:visibility_timeout]
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_messages
|
43
|
+
generate_messages(source_queue_url, 5) + generate_messages(dlq_queue_url, 3)
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_messages(queue_url, count=1)
|
47
|
+
messages = []
|
48
|
+
count.times do |time|
|
49
|
+
messages << sqs.send_message(queue_url: queue_url, message_body: "Test_#{time}",
|
50
|
+
message_attributes: {"foo_class"=> {string_value: "FooWorker", data_type: "String"}})
|
51
|
+
end
|
52
|
+
messages
|
53
|
+
end
|
54
|
+
end
|
data/sqs_web.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqs_web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathaniel Ritholtz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -156,9 +156,12 @@ files:
|
|
156
156
|
- lib/sqs_web/application/views/working.erb
|
157
157
|
- lib/sqs_web/railtie.rb
|
158
158
|
- spec/integration/app_spec.rb
|
159
|
+
- spec/integration/dlq_console_spec.rb
|
160
|
+
- spec/integration/overview_spec.rb
|
159
161
|
- spec/spec_helper.rb
|
160
162
|
- spec/support/fake_sqs.rb
|
161
163
|
- spec/support/rails_app.rb
|
164
|
+
- spec/support/shared_context.rb
|
162
165
|
- sqs_web.gemspec
|
163
166
|
homepage: https://github.com/nritholtz/sqs_web
|
164
167
|
licenses:
|
@@ -186,6 +189,9 @@ specification_version: 4
|
|
186
189
|
summary: Web interface for SQS inspired by delayed_job_web
|
187
190
|
test_files:
|
188
191
|
- spec/integration/app_spec.rb
|
192
|
+
- spec/integration/dlq_console_spec.rb
|
193
|
+
- spec/integration/overview_spec.rb
|
189
194
|
- spec/spec_helper.rb
|
190
195
|
- spec/support/fake_sqs.rb
|
191
196
|
- spec/support/rails_app.rb
|
197
|
+
- spec/support/shared_context.rb
|