fastly_nsq 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +1 -1
  5. data/Gemfile +0 -2
  6. data/README.md +56 -14
  7. data/Rakefile +4 -9
  8. data/examples/Rakefile +36 -0
  9. data/fastly_nsq.gemspec +1 -2
  10. data/lib/fastly_nsq/message_queue/consumer.rb +5 -1
  11. data/lib/fastly_nsq/message_queue/listener.rb +27 -4
  12. data/lib/fastly_nsq/message_queue/producer.rb +5 -1
  13. data/lib/fastly_nsq/rake_task.rb +40 -0
  14. data/lib/fastly_nsq/sample_message_processor.rb +16 -12
  15. data/lib/fastly_nsq/version.rb +1 -1
  16. data/{test/lib/fastly_nsq/fake_message_queue_test.rb → spec/lib/fastly_nsq/fake_message_queue_spec.rb} +12 -12
  17. data/{test/lib/fastly_nsq/fastly_nsq_test.rb → spec/lib/fastly_nsq/fastly_nsq_spec.rb} +3 -3
  18. data/spec/lib/fastly_nsq/message_queue/consumer_spec.rb +93 -0
  19. data/spec/lib/fastly_nsq/message_queue/listener_spec.rb +78 -0
  20. data/spec/lib/fastly_nsq/message_queue/producer_spec.rb +84 -0
  21. data/{test/lib/fastly_nsq/message_queue/strategy.rb → spec/lib/fastly_nsq/message_queue/strategy_spec.rb} +5 -7
  22. data/{test/lib/fastly_nsq/sample_message_processor_test.rb → spec/lib/fastly_nsq/sample_message_processor_spec.rb} +8 -22
  23. data/spec/spec_helper.rb +44 -0
  24. data/spec/support/env_helpers.rb +19 -0
  25. data/test/lib/fastly_nsq/rake_task_test.rb +68 -0
  26. metadata +17 -33
  27. data/test/lib/fastly_nsq/message_queue/consumer_test.rb +0 -59
  28. data/test/lib/fastly_nsq/message_queue/listener_test.rb +0 -45
  29. data/test/lib/fastly_nsq/message_queue/producer_test.rb +0 -54
  30. data/test/test_helper.rb +0 -49
@@ -1,10 +1,10 @@
1
- require 'test_helper'
1
+ require 'spec_helper'
2
2
  require 'fastly_nsq'
3
3
 
4
- describe FastlyNsq do
4
+ RSpec.describe FastlyNsq do
5
5
  it 'has a version number' do
6
6
  version = FastlyNsq.const_get('VERSION')
7
7
 
8
- assert(!version.empty?, 'should have a VERSION constant')
8
+ expect(version).not_to be_empty
9
9
  end
10
10
  end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe MessageQueue::Consumer do
4
+ describe '#connection' do
5
+ describe 'when using the real queue' do
6
+ it 'returns an instance of the queue consumer' do
7
+ use_real_connection do
8
+ allow(Nsq::Consumer).to receive(:new)
9
+ topic = 'death_star'
10
+ channel = 'star_killer_base'
11
+
12
+ MessageQueue::Consumer.new(topic: topic, channel: channel).connection
13
+
14
+ expect(Nsq::Consumer).to have_received(:new).
15
+ with(
16
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
17
+ topic: topic,
18
+ channel: channel,
19
+ ).at_least(:once)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe 'when using the fake queue' do
25
+ it 'returns an instance of the queue consumer' do
26
+ use_fake_connection do
27
+ allow(FakeMessageQueue::Consumer).to receive(:new)
28
+ topic = 'death_star'
29
+ channel = 'star_killer_base'
30
+
31
+ MessageQueue::Consumer.new(topic: topic, channel: channel).connection
32
+
33
+ expect(FakeMessageQueue::Consumer).to have_received(:new).
34
+ with(
35
+ nsqlookupd: ENV.fetch('NSQLOOKUPD_HTTP_ADDRESS'),
36
+ topic: topic,
37
+ channel: channel,
38
+ ).at_least(:once)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ describe 'when the ENV is set incorrectly' do
45
+ it 'raises with a helpful error' do
46
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
47
+ topic = 'death_star'
48
+ channel = 'star_killer_base'
49
+
50
+ consumer = MessageQueue::Consumer.new(topic: topic, channel: channel)
51
+
52
+ expect{ consumer.connection }.to raise_error(InvalidParameterError)
53
+ end
54
+ end
55
+
56
+ describe '#terminate' do
57
+ describe 'when using the real queue' do
58
+ it 'closes the connection' do
59
+ use_real_connection do
60
+ consumer = double('Consumer', connection: nil, terminate: nil)
61
+ allow(Nsq::Consumer).to receive(:new).and_return(consumer)
62
+ topic = 'death_star'
63
+ channel = 'star_killer_base'
64
+ params = { topic: topic, channel: channel }
65
+
66
+ live_consumer = MessageQueue::Consumer.new(params)
67
+ live_consumer.connection
68
+ live_consumer.terminate
69
+
70
+ expect(consumer).to have_received(:terminate)
71
+ end
72
+ end
73
+ end
74
+
75
+ describe 'when using the fake queue' do
76
+ it 'closes the connection' do
77
+ use_fake_connection do
78
+ consumer = double('Consumer', connection: nil, terminate: nil)
79
+ allow(FakeMessageQueue::Consumer).to receive(:new).and_return(consumer)
80
+ topic = 'death_star'
81
+ channel = 'star_killer_base'
82
+ params = { topic: topic, channel: channel }
83
+
84
+ live_consumer = MessageQueue::Consumer.new(params)
85
+ live_consumer.connection
86
+ live_consumer.terminate
87
+
88
+ expect(consumer).to have_received(:terminate)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe MessageQueue::Listener do
4
+ describe '#process_next_message' do
5
+ it 'pass the topic and channel to the consumer' do
6
+ allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
7
+ message = double('Message', finish: nil, body: nil)
8
+ connection = double('Connection', pop: message, terminate: nil)
9
+ consumer = double('Consumer', connection: connection)
10
+ allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
11
+ topic = 'minitest'
12
+ channel = 'northstar'
13
+
14
+ MessageQueue::Listener.new(topic: topic, channel: channel).
15
+ process_next_message
16
+
17
+ expect(MessageQueue::Consumer).to have_received(:new).
18
+ with(topic: topic, channel: channel)
19
+ end
20
+
21
+ it 'processes the message' do
22
+ process_message = double(go: nil)
23
+ allow(MessageProcessor).to receive(:new).and_return(process_message)
24
+ message_body = { data: 'value' }.to_json
25
+ message = double('Message', finish: nil, body: message_body)
26
+ connection = double('Connection', pop: message, terminate: nil)
27
+ consumer = double('Consumer', connection: connection)
28
+ allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
29
+ topic = 'minitest'
30
+ channel = 'northstar'
31
+
32
+ MessageQueue::Listener.new(topic: topic, channel: channel).
33
+ process_next_message
34
+
35
+ expect(MessageProcessor).to have_received(:new).with(message_body)
36
+ expect(process_message).to have_received(:go)
37
+ end
38
+
39
+ it 'finishes the message' do
40
+ allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
41
+ message = double('Message', finish: nil, body: nil)
42
+ connection = double('Connection', pop: message, terminate: nil)
43
+ consumer = double('Consumer', connection: connection)
44
+ allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
45
+ topic = 'minitest'
46
+ channel = 'northstar'
47
+
48
+ MessageQueue::Listener.new(topic: topic, channel: channel).
49
+ process_next_message
50
+
51
+ expect(message).to have_received(:finish)
52
+ end
53
+ end
54
+
55
+ describe '#go' do
56
+ describe 'when a SIGTERM is received' do
57
+ it 'closes the consumer connection' do
58
+ allow(SampleMessageProcessor).to receive_message_chain(:new, :go)
59
+ message = double(finish: nil, body: nil)
60
+ connection = double('Connection', pop: message, terminate: nil)
61
+ consumer = double('Consumer', connection: connection)
62
+ allow(MessageQueue::Consumer).to receive(:new).and_return(consumer)
63
+ topic = 'minitest'
64
+ channel = 'northstar'
65
+
66
+ pid = fork do
67
+ MessageQueue::Listener.new(topic: topic, channel: channel).go
68
+ end
69
+
70
+ Process.kill('TERM', pid)
71
+
72
+ # Success for this test is to expect it to complete
73
+ # Note: We are not testing the SIGINT case because it orphans the test
74
+ # Ruby process and is sort of meaningless as a test.
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe MessageQueue::Producer do
4
+ describe '#connection' do
5
+ describe 'when using the real queue' do
6
+ it 'returns an instance of the queue producer' do
7
+ use_real_connection do
8
+ allow(Nsq::Producer).to receive(:new)
9
+ topic = 'death_star'
10
+
11
+ MessageQueue::Producer.new(topic: topic).connection
12
+
13
+ expect(Nsq::Producer).to have_received(:new).
14
+ with(
15
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
16
+ topic: topic,
17
+ ).at_least(:once)
18
+ end
19
+ end
20
+ end
21
+
22
+ describe 'when using the fake queue' do
23
+ it 'returns an instance of the queue producer' do
24
+ use_fake_connection do
25
+ allow(FakeMessageQueue::Producer).to receive(:new)
26
+ topic = 'death_star'
27
+
28
+ MessageQueue::Producer.new(topic: topic).connection
29
+
30
+ expect(FakeMessageQueue::Producer).to have_received(:new).
31
+ with(
32
+ nsqd: ENV.fetch('NSQD_TCP_ADDRESS'),
33
+ topic: topic,
34
+ ).at_least(:once)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe 'when the ENV is set incorrectly' do
40
+ it 'raises with a helpful error' do
41
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
42
+ topic = 'death_star'
43
+
44
+ producer = MessageQueue::Producer.new(topic: topic)
45
+
46
+ expect{ producer.connection }.to raise_error(InvalidParameterError)
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '#terminate' do
52
+ describe 'when using the real queue' do
53
+ it 'closes the connection' do
54
+ use_real_connection do
55
+ producer = double('Producer', connection: nil, terminate: nil)
56
+ allow(Nsq::Producer).to receive(:new).and_return(producer)
57
+ topic = 'death_star'
58
+
59
+ live_producer = MessageQueue::Producer.new(topic: topic)
60
+ live_producer.connection
61
+ live_producer.terminate
62
+
63
+ expect(producer).to have_received(:terminate)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe 'when using the fake queue' do
69
+ it 'closes the connection' do
70
+ use_fake_connection do
71
+ producer = double('Producer', connection: nil, terminate: nil)
72
+ allow(FakeMessageQueue::Producer).to receive(:new).and_return(producer)
73
+ topic = 'death_star'
74
+
75
+ live_producer = MessageQueue::Producer.new(topic: topic)
76
+ live_producer.connection
77
+ live_producer.terminate
78
+
79
+ expect(producer).to have_received(:terminate)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -1,6 +1,6 @@
1
- require 'test_helper'
1
+ require 'spec_helper'
2
2
 
3
- describe Strategy do
3
+ RSpec.describe Strategy do
4
4
  describe '.for_queue' do
5
5
  describe 'when using the fake queue' do
6
6
  it 'returns the strategy based on the ENV variable' do
@@ -9,7 +9,7 @@ describe Strategy do
9
9
 
10
10
  strategy = Strategy.for_queue
11
11
 
12
- assert equal FakeMessageQueue, strategy
12
+ expect(strategy).to eq FakeMessageQueue
13
13
  end
14
14
  end
15
15
  end
@@ -21,7 +21,7 @@ describe Strategy do
21
21
 
22
22
  strategy = Strategy.for_queue
23
23
 
24
- assert equal Nsq, strategy
24
+ expect(strategy).to eq Nsq
25
25
  end
26
26
  end
27
27
  end
@@ -30,9 +30,7 @@ describe Strategy do
30
30
  it 'raises with a helpful error' do
31
31
  allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return('taco')
32
32
 
33
- assert_raises(InvalidParameterError) do
34
- Strategy.for_queue
35
- end
33
+ expect{ Strategy.for_queue }.to raise_error(InvalidParameterError)
36
34
  end
37
35
  end
38
36
  end
@@ -1,40 +1,27 @@
1
- require 'test_helper'
1
+ require 'spec_helper'
2
2
 
3
- describe SampleMessageProcessor do
3
+ RSpec.describe SampleMessageProcessor do
4
4
  describe '#start' do
5
5
  it 'enqueues the appropriate message processor' do
6
6
  data = { 'key' => 'value' }
7
- body = { 'event_type' => 'heartbeat', 'data' => data }.to_json
8
- message = double('Message', body: body, finish: nil)
7
+ message_body = { 'event_type' => 'heartbeat', 'data' => data }.to_json
9
8
  allow(HeartbeatWorker).to receive(:perform_async)
10
9
 
11
- SampleMessageProcessor.new(message).go
10
+ SampleMessageProcessor.new(message_body).go
12
11
 
13
12
  expect(HeartbeatWorker).to have_received(:perform_async).with(data)
14
13
  end
15
14
 
16
- it 'finishes the message' do
17
- data = { 'key' => 'value' }
18
- body = { 'event_type' => 'heartbeat', 'data' => data }.to_json
19
- message = double('Message', body: body, finish: nil)
20
- allow(HeartbeatWorker).to receive(:perform_async)
21
-
22
- SampleMessageProcessor.new(message).go
23
-
24
- expect(message).to have_received(:finish)
25
- end
26
-
27
15
  describe 'when the message event_type is not known' do
28
16
  it 'uses the null object processor' do
29
17
  data = { 'sample_key' => 'sample value' }
30
- body = {
18
+ message_body = {
31
19
  'event_type' => 'unregistered_message_type',
32
20
  'data' => data,
33
21
  }.to_json
34
- message = double('Message', body: body, finish: nil)
35
22
  allow(UnknownMessageWorker).to receive(:perform_async)
36
23
 
37
- SampleMessageProcessor.new(message).go
24
+ SampleMessageProcessor.new(message_body).go
38
25
 
39
26
  expect(UnknownMessageWorker).to have_received(:perform_async).with(data)
40
27
  end
@@ -43,14 +30,13 @@ describe SampleMessageProcessor do
43
30
  describe 'when the message lacks an event_type' do
44
31
  it 'uses the null object processor' do
45
32
  data = { 'sample_key' => 'sample value' }
46
- body = {
33
+ message_body = {
47
34
  'not_the_event_type_key' => 'unregistered_message_type',
48
35
  'data' => data,
49
36
  }.to_json
50
- message = double('Message', body: body, finish: nil)
51
37
  allow(UnknownMessageWorker).to receive(:perform_async)
52
38
 
53
- SampleMessageProcessor.new(message).go
39
+ SampleMessageProcessor.new(message_body).go
54
40
 
55
41
  expect(UnknownMessageWorker).to have_received(:perform_async).with(data)
56
42
  end
@@ -0,0 +1,44 @@
1
+ require 'fastly_nsq'
2
+ require 'awesome_print'
3
+ require 'pry-byebug'
4
+
5
+ require_relative '../lib/fastly_nsq/sample_message_processor'
6
+ require_relative 'support/env_helpers'
7
+
8
+ MessageProcessor = SampleMessageProcessor
9
+
10
+ RSpec.configure do |config|
11
+ config.expect_with :rspec do |expectations|
12
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
13
+ end
14
+
15
+ config.mock_with :rspec do |mocks|
16
+ mocks.verify_partial_doubles = true
17
+ end
18
+
19
+ config.default_formatter = 'progress'
20
+ config.disable_monkey_patching!
21
+ config.example_status_persistence_file_path = 'spec/examples.txt'
22
+ config.filter_run :focus
23
+ config.order = :random
24
+ config.profile_examples = false
25
+ config.run_all_when_everything_filtered = true
26
+ Kernel.srand config.seed
27
+
28
+ if config.files_to_run.one?
29
+ config.default_formatter = 'doc'
30
+ end
31
+
32
+ config.before(:each) do
33
+ load_sample_environment_variables
34
+ FakeMessageQueue.reset!
35
+ end
36
+
37
+ def load_sample_environment_variables
38
+ env_file = File.open('env_configuration_for_local_gem_tests.yml')
39
+
40
+ YAML.load(env_file).each do |key, value|
41
+ ENV[key.to_s] = value
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ module EnvHelpers
2
+ def use_fake_connection
3
+ MessageQueue::TRUTHY_VALUES.each do |yes|
4
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(yes)
5
+ yield
6
+ end
7
+ end
8
+
9
+ def use_real_connection
10
+ MessageQueue::FALSY_VALUES.each do |no|
11
+ allow(ENV).to receive(:[]).with('FAKE_QUEUE').and_return(no)
12
+ yield
13
+ end
14
+ end
15
+ end
16
+
17
+ RSpec.configure do |config|
18
+ config.include EnvHelpers
19
+ end
@@ -0,0 +1,68 @@
1
+ require 'test_helper'
2
+ require 'fastly_nsq/rake_task'
3
+
4
+ describe MessageQueue::RakeTask do
5
+ before(:each) do
6
+ Rake::Task['begin_listening'].clear if Rake::Task.task_defined?('begin_listening')
7
+ end
8
+
9
+ describe 'defining tasks' do
10
+ it 'creates a begin_listening task' do
11
+ MessageQueue::RakeTask.new
12
+
13
+ allow_any_instance_of(MessageQueue::RakeTask).to receive(:output) { nil }
14
+ assert_equal true, Rake::Task.task_defined?(:begin_listening)
15
+ end
16
+
17
+ it 'creates a named task' do
18
+ MessageQueue::RakeTask.new(:test_name)
19
+
20
+ allow_any_instance_of(MessageQueue::RakeTask).to receive(:output) { nil }
21
+ assert_equal true, Rake::Task.task_defined?(:test_name)
22
+ end
23
+ end
24
+
25
+ describe 'running tasks' do
26
+ it 'runs with inline options defined' do
27
+ MessageQueue::RakeTask.new(:begin_listening, [:topic, :channel])
28
+
29
+ dbl = double('go', go: nil)
30
+ expect(MessageQueue::Listener).to receive(:new).
31
+ with(topic: 'dwarf', channel: 'star').
32
+ and_return(dbl)
33
+
34
+ allow_any_instance_of(MessageQueue::RakeTask).to receive(:output) { nil }
35
+ Rake::Task['begin_listening'].execute(topic: 'dwarf', channel: 'star')
36
+ end
37
+
38
+ it 'runs with specified options if a block is given' do
39
+ MessageQueue::RakeTask.new do |task|
40
+ task.topic = 'dwarf'
41
+ task.channel = 'star'
42
+ end
43
+
44
+ dbl = double('go', go: nil)
45
+ expect(MessageQueue::Listener).to receive(:new).
46
+ with(topic: 'dwarf', channel: 'star').
47
+ and_return(dbl)
48
+
49
+ allow_any_instance_of(MessageQueue::RakeTask).to receive(:output) { nil }
50
+ Rake::Task['begin_listening'].execute(topic: 'dwarf', channel: 'star')
51
+ end
52
+
53
+ it 'uses inline over block' do
54
+ MessageQueue::RakeTask.new(:begin_listening, [:topic, :channel]) do |task|
55
+ task.topic = 'loud'
56
+ task.channel = 'noise'
57
+ end
58
+
59
+ dbl = double('go', go: nil)
60
+ expect(MessageQueue::Listener).to receive(:new).
61
+ with(topic: 'dwarf', channel: 'star').
62
+ and_return(dbl)
63
+
64
+ allow_any_instance_of(MessageQueue::RakeTask).to receive(:output) { nil }
65
+ Rake::Task['begin_listening'].execute(topic: 'dwarf', channel: 'star')
66
+ end
67
+ end
68
+ end