sqs_web 0.0.1 → 0.0.2
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 +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
|