rails-pipeline 1.1.1
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/MIT-LICENSE +20 -0
- data/README.md +227 -0
- data/Rakefile +27 -0
- data/bin/pipeline +138 -0
- data/bin/redis-to-ironmq.rb +20 -0
- data/lib/rails-pipeline.rb +34 -0
- data/lib/rails-pipeline/emitter.rb +121 -0
- data/lib/rails-pipeline/handlers/activerecord_crud.rb +35 -0
- data/lib/rails-pipeline/handlers/base_handler.rb +19 -0
- data/lib/rails-pipeline/handlers/logger.rb +13 -0
- data/lib/rails-pipeline/ironmq_publisher.rb +37 -0
- data/lib/rails-pipeline/ironmq_pulling_subscriber.rb +96 -0
- data/lib/rails-pipeline/ironmq_subscriber.rb +21 -0
- data/lib/rails-pipeline/pipeline_version.rb +40 -0
- data/lib/rails-pipeline/protobuf/encrypted_message.pb.rb +37 -0
- data/lib/rails-pipeline/protobuf/encrypted_message.proto +18 -0
- data/lib/rails-pipeline/redis_forwarder.rb +207 -0
- data/lib/rails-pipeline/redis_ironmq_forwarder.rb +12 -0
- data/lib/rails-pipeline/redis_publisher.rb +71 -0
- data/lib/rails-pipeline/sns_publisher.rb +62 -0
- data/lib/rails-pipeline/subscriber.rb +185 -0
- data/lib/rails-pipeline/symmetric_encryptor.rb +127 -0
- data/lib/rails-pipeline/version.rb +3 -0
- data/lib/tasks/rails-pipeline_tasks.rake +4 -0
- data/spec/emitter_spec.rb +141 -0
- data/spec/handlers/activerecord_crud_spec.rb +100 -0
- data/spec/handlers/logger_spec.rb +42 -0
- data/spec/ironmp_pulling_subscriber_spec.rb +98 -0
- data/spec/ironmq_publisher_spec.rb +37 -0
- data/spec/pipeline_version_spec.rb +35 -0
- data/spec/redis_forwarder_spec.rb +99 -0
- data/spec/redis_publisher_spec.rb +36 -0
- data/spec/sns_publisher_spec.rb +28 -0
- data/spec/subscriber_spec.rb +278 -0
- data/spec/symmetric_encryptor_spec.rb +21 -0
- metadata +175 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
# Mixin to enable symmetric encryption/decryption for pipeline, using protocol
|
2
|
+
# buffers on the wire.
|
3
|
+
|
4
|
+
require "rails-pipeline/protobuf/encrypted_message.pb"
|
5
|
+
|
6
|
+
module RailsPipeline
|
7
|
+
|
8
|
+
module SymmetricEncryptor
|
9
|
+
Error = Class.new(StandardError)
|
10
|
+
NoApiKeyError = Class.new(Error) do
|
11
|
+
def message
|
12
|
+
"You need to set the env variable PIPELINE_API_KEY to emit messages"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
# Allow configuration via initializer
|
18
|
+
@@secret = nil
|
19
|
+
def _secret
|
20
|
+
@@secret.nil? ? ENV.fetch("PIPELINE_SECRET", Rails.application.config.secret_token) : @@secret
|
21
|
+
end
|
22
|
+
|
23
|
+
def secret=(secret)
|
24
|
+
@@secret = secret
|
25
|
+
end
|
26
|
+
|
27
|
+
@@api_key = nil
|
28
|
+
def _api_key
|
29
|
+
api_key = @@api_key.nil? ? ENV["PIPELINE_API_KEY"] : @@api_key
|
30
|
+
if api_key.blank?
|
31
|
+
raise NoApiKeyError.new
|
32
|
+
end
|
33
|
+
return api_key
|
34
|
+
end
|
35
|
+
|
36
|
+
def api_key=(api_key)
|
37
|
+
@@api_key = api_key
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.included(base)
|
42
|
+
base.extend ClassMethods
|
43
|
+
end
|
44
|
+
|
45
|
+
module ClassMethods
|
46
|
+
|
47
|
+
def encrypt(plaintext, owner_info: nil, type_info: nil, topic: nil, event_type: nil)
|
48
|
+
# Inititalize a symmetric cipher for encryption
|
49
|
+
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
50
|
+
cipher.encrypt
|
51
|
+
|
52
|
+
# Create a random salt
|
53
|
+
salt = OpenSSL::Random.random_bytes(16)
|
54
|
+
|
55
|
+
# Create a PKCS5 key from the rails password
|
56
|
+
# NOTE: suggested way of doing this is by cipher.random_key
|
57
|
+
# and then we would store the key on the user.
|
58
|
+
key = _key(salt)
|
59
|
+
|
60
|
+
# Set the key and get a random initialization vector
|
61
|
+
cipher.key = key
|
62
|
+
iv = cipher.random_iv
|
63
|
+
|
64
|
+
# Do the encryption
|
65
|
+
ciphertext = cipher.update(plaintext) + cipher.final
|
66
|
+
uuid = SecureRandom.uuid
|
67
|
+
return RailsPipeline::EncryptedMessage.new(
|
68
|
+
uuid: uuid,
|
69
|
+
salt: Base64.encode64(salt),
|
70
|
+
iv: Base64.encode64(iv),
|
71
|
+
ciphertext: Base64.encode64(ciphertext),
|
72
|
+
owner_info: owner_info,
|
73
|
+
type_info: type_info,
|
74
|
+
topic: topic,
|
75
|
+
event_type: _event_type_value(event_type),
|
76
|
+
api_key: _api_key,
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Message is an instance of EncryptedMessage
|
81
|
+
def decrypt(message)
|
82
|
+
salt = Base64.decode64(message.salt)
|
83
|
+
key = _key(salt)
|
84
|
+
cipher = OpenSSL::Cipher::AES256.new(:CBC)
|
85
|
+
# Initialize for decryption
|
86
|
+
cipher.decrypt
|
87
|
+
|
88
|
+
# Set up key and iv
|
89
|
+
cipher.key = key
|
90
|
+
cipher.iv = Base64.decode64(message.iv)
|
91
|
+
|
92
|
+
# Decrypt
|
93
|
+
decoded = Base64.decode64(message.ciphertext)
|
94
|
+
plaintext = cipher.update(decoded) + cipher.final
|
95
|
+
|
96
|
+
return plaintext
|
97
|
+
end
|
98
|
+
|
99
|
+
def _secret
|
100
|
+
RailsPipeline::SymmetricEncryptor._secret
|
101
|
+
end
|
102
|
+
|
103
|
+
def _api_key
|
104
|
+
RailsPipeline::SymmetricEncryptor._api_key
|
105
|
+
end
|
106
|
+
|
107
|
+
def _key(salt)
|
108
|
+
iter = 10000
|
109
|
+
key_len = 32
|
110
|
+
key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(_secret, salt, iter, key_len)
|
111
|
+
return key
|
112
|
+
end
|
113
|
+
|
114
|
+
def _event_type_value(event_type)
|
115
|
+
case event_type
|
116
|
+
when :create
|
117
|
+
RailsPipeline::EncryptedMessage::EventType::CREATED
|
118
|
+
when :update
|
119
|
+
RailsPipeline::EncryptedMessage::EventType::UPDATED
|
120
|
+
when :destroy
|
121
|
+
RailsPipeline::EncryptedMessage::EventType::DELETED
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require_relative 'pipeline_helper'
|
4
|
+
|
5
|
+
|
6
|
+
describe RailsPipeline::Emitter do
|
7
|
+
before do
|
8
|
+
@test_emitter = TestEmitter.new({foo: "bar"}, without_protection: true)
|
9
|
+
@test_model = TestModelWithTable.new
|
10
|
+
@default_emitter = DefaultEmitter.new({foo: "baz"}, without_protection: true)
|
11
|
+
TestModelWithTable.pipeline_method_cache = {}
|
12
|
+
TestEmitter.pipeline_method_cache = {}
|
13
|
+
DefaultEmitter.pipeline_method_cache = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should derive the topic name" do
|
17
|
+
TestEmitter.topic_name.should eql "harrys-#{Rails.env}-v1-test_emitters"
|
18
|
+
TestEmitter.topic_name("2_1").should eql "harrys-#{Rails.env}-v2-test_emitters"
|
19
|
+
TestEmitter.topic_name("2").should eql "harrys-#{Rails.env}-v2-test_emitters"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should detect all pipeline versions in class" do
|
23
|
+
pipeline_versions = TestEmitter.pipeline_versions
|
24
|
+
pipeline_versions.length.should eql 2
|
25
|
+
pipeline_versions.should include "1_1"
|
26
|
+
pipeline_versions.should include "2_0"
|
27
|
+
|
28
|
+
DefaultEmitter.pipeline_versions.length.should eql 1
|
29
|
+
DefaultEmitter.pipeline_versions.should eql ["1_0"]
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with only default version" do
|
33
|
+
it "should produce all attributes" do
|
34
|
+
data = @default_emitter.to_pipeline_1_0
|
35
|
+
expect(data.foo).to eq("baz")
|
36
|
+
expect(data.class).to eq(DefaultEmitter_1_0)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should emit one version" do
|
40
|
+
@default_emitter.should_receive(:publish).once
|
41
|
+
@default_emitter.emit
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should encrypt the payload" do
|
45
|
+
DefaultEmitter.should_receive(:encrypt).once { |data|
|
46
|
+
obj = DefaultEmitter_1_0.parse(data)
|
47
|
+
expect(obj.foo).to eq "baz"
|
48
|
+
}.and_call_original
|
49
|
+
@default_emitter.should_receive(:publish).once
|
50
|
+
@default_emitter.emit
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have the correct encrypted payload" do
|
54
|
+
DefaultEmitter.should_receive(:encrypt).once.and_call_original
|
55
|
+
# Just verify that the right encrypted data gets sent to publish
|
56
|
+
@default_emitter.should_receive(:publish).once do |topic, serialized_message|
|
57
|
+
topic.should eql "harrys-#{Rails.env}-v1-default_emitters"
|
58
|
+
message = RailsPipeline::EncryptedMessage.parse(serialized_message)
|
59
|
+
expect(message.type_info).to eq(DefaultEmitter_1_0.to_s)
|
60
|
+
|
61
|
+
plaintext = DefaultEmitter.decrypt(message)
|
62
|
+
obj = DefaultEmitter_1_0.parse(plaintext)
|
63
|
+
expect(obj.foo).to eq("baz")
|
64
|
+
end
|
65
|
+
@default_emitter.emit
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with defined version" do
|
70
|
+
it "should produce expected version when called explicitly" do
|
71
|
+
data = @test_emitter.to_pipeline_1_1
|
72
|
+
data.foo.should eql "bar"
|
73
|
+
data.extrah.should eql "hi"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should emit multiple versions" do
|
77
|
+
@test_emitter.should_receive(:publish).twice
|
78
|
+
@test_emitter.emit
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'event type' do
|
83
|
+
context 'created' do
|
84
|
+
it "sets event type correctly in enveloppe" do
|
85
|
+
@test_model.should_receive(:publish).once do |topic, serialized_message|
|
86
|
+
topic.should eq("harrys-#{Rails.env}-v1-test_model_with_tables")
|
87
|
+
message = RailsPipeline::EncryptedMessage.parse(serialized_message)
|
88
|
+
expect(message.event_type).to eq(RailsPipeline::EncryptedMessage::EventType::CREATED)
|
89
|
+
end
|
90
|
+
@test_model.save!
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'updated' do
|
95
|
+
it "sets event type correctly in enveloppe" do
|
96
|
+
@test_model.save!
|
97
|
+
expect(@test_model).to receive(:publish).once do |topic, serialized_message|
|
98
|
+
expect(topic).to eq("harrys-#{Rails.env}-v1-test_model_with_tables")
|
99
|
+
message = RailsPipeline::EncryptedMessage.parse(serialized_message)
|
100
|
+
expect(message.event_type).to eq(RailsPipeline::EncryptedMessage::EventType::UPDATED)
|
101
|
+
end
|
102
|
+
@test_model.save!
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'deleted' do
|
107
|
+
it "sets event type correctly in enveloppe" do
|
108
|
+
@test_model.save!
|
109
|
+
expect(@test_model).to receive(:publish).once do |topic, serialized_message|
|
110
|
+
expect(topic).to eq("harrys-#{Rails.env}-v1-test_model_with_tables")
|
111
|
+
message = RailsPipeline::EncryptedMessage.parse(serialized_message)
|
112
|
+
expect(message.event_type).to eq(RailsPipeline::EncryptedMessage::EventType::DELETED)
|
113
|
+
end
|
114
|
+
@test_model.destroy
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'methods cache' do
|
120
|
+
context 'empty cache' do
|
121
|
+
before { @test_model.save! }
|
122
|
+
it 'caches the pipeline versions' do
|
123
|
+
TestModelWithTable.pipeline_method_cache[RailsPipeline::PipelineVersion.new('1_1')].should eq(:to_pipeline_1_1)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'non empty cache' do
|
128
|
+
|
129
|
+
before do
|
130
|
+
# warms the cache
|
131
|
+
TestModelWithTable.pipeline_versions
|
132
|
+
end
|
133
|
+
it "reads from cache" do
|
134
|
+
version = RailsPipeline::PipelineVersion.new('1_1')
|
135
|
+
TestModelWithTable.should_not_receive(:instance_methods)
|
136
|
+
# TestModelWithTable.pipeline_method_cache.should_receive(:[]).with(version).once.and_call_original
|
137
|
+
@test_model.save!
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pipeline_helper'
|
3
|
+
|
4
|
+
describe RailsPipeline::SubscriberHandler::ActiveRecordCRUD do
|
5
|
+
describe 'handle payload event type' do
|
6
|
+
let(:handler) {
|
7
|
+
RailsPipeline::SubscriberHandler::ActiveRecordCRUD.new(
|
8
|
+
payload, target_class: subscriber.target_class(payload), event_type: event)
|
9
|
+
}
|
10
|
+
let(:subscriber) { TestSubscriber.new }
|
11
|
+
let(:test_message) { test_model.create_message("1_1", event) }
|
12
|
+
let(:payload_str) { subscriber.class.decrypt(test_message) }
|
13
|
+
let(:clazz) { Object.const_get(test_message.type_info) }
|
14
|
+
let(:payload) { clazz.parse(payload_str) }
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
RailsPipeline::Subscriber.register(TestEmitter_1_1, TestModelWithTable)
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:each) { TestModelWithTable.delete_all }
|
21
|
+
|
22
|
+
context 'CREATED' do
|
23
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::CREATED }
|
24
|
+
let(:test_model) { TestModelWithTable.new({id: 42, foo: 'bar'}, without_protection: true) }
|
25
|
+
|
26
|
+
it "should create an object" do
|
27
|
+
expect {
|
28
|
+
handler.handle_payload
|
29
|
+
}.to change(TestModelWithTable, :count).by(1)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should create with correct attributes" do
|
33
|
+
new_object = handler.handle_payload
|
34
|
+
new_object.should be_persisted
|
35
|
+
new_object.id.should eq(42)
|
36
|
+
new_object.foo.should eq('bar')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should log if creation failed" do
|
40
|
+
TestModelWithTable.create({id: 42}, without_protection: true)
|
41
|
+
RailsPipeline.logger.should_receive(:error).with("Could not handle payload: #{payload.inspect}, event_type: #{event}")
|
42
|
+
handler.handle_payload
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'UPDATED' do
|
47
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::UPDATED }
|
48
|
+
let(:test_model) { TestModelWithTable.new({id: 42, foo: 'bar'}, without_protection: true) }
|
49
|
+
|
50
|
+
it "should update existing object" do
|
51
|
+
test_model.save!
|
52
|
+
test_model.foo = 'qux'
|
53
|
+
object = handler.handle_payload
|
54
|
+
object.should be_persisted
|
55
|
+
object.id.should eq(42)
|
56
|
+
object.foo.should eq('qux')
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should log if update failed" do
|
60
|
+
RailsPipeline.logger.should_receive(:error).with("Could not handle payload: #{payload.inspect}, event_type: #{event}")
|
61
|
+
handler.handle_payload
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'DELETED' do
|
66
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::DELETED }
|
67
|
+
let(:test_model) { TestModelWithTable.new({id: 42, foo: 'bar'}, without_protection: true) }
|
68
|
+
|
69
|
+
it "should update existing object" do
|
70
|
+
test_model.save!
|
71
|
+
object = handler.handle_payload
|
72
|
+
object.should be_destroyed
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should log if update failed" do
|
76
|
+
RailsPipeline.logger.should_receive(:error).with("Could not handle payload: #{payload.inspect}, event_type: #{event}")
|
77
|
+
handler.handle_payload
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'attributes' do
|
83
|
+
let(:handler) {
|
84
|
+
RailsPipeline::SubscriberHandler::ActiveRecordCRUD.new(
|
85
|
+
payload, target_class: subscriber.target_class(payload), event_type: event)
|
86
|
+
}
|
87
|
+
let(:subscriber) { TestSubscriber.new }
|
88
|
+
let(:test_model) { TestModelWithTable.new({foo: 'bar'}, without_protection: true) }
|
89
|
+
let(:test_message) { test_model.create_message("1_1", event) }
|
90
|
+
let(:payload_str) { subscriber.class.decrypt(test_message) }
|
91
|
+
let(:clazz) { Object.const_get(test_message.type_info) }
|
92
|
+
let(:payload) { clazz.parse(payload_str) }
|
93
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::CREATED }
|
94
|
+
|
95
|
+
it 'converts datetime correctly' do
|
96
|
+
test_model.save!
|
97
|
+
handler._attributes(payload)[:created_at].should be_an_instance_of(DateTime)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pipeline_helper'
|
3
|
+
|
4
|
+
describe RailsPipeline::SubscriberHandler::Logger do
|
5
|
+
describe 'handle payload event type' do
|
6
|
+
let(:handler) {
|
7
|
+
RailsPipeline::SubscriberHandler::Logger.new(
|
8
|
+
payload, envelope: test_message)
|
9
|
+
}
|
10
|
+
let(:test_model) { TestModelWithTable.new({id: 42, foo: 'bar'}, without_protection: true) }
|
11
|
+
let(:subscriber) { TestSubscriber.new }
|
12
|
+
let(:test_message) { test_model.create_message("1_1", event) }
|
13
|
+
let(:payload_str) { subscriber.class.decrypt(test_message) }
|
14
|
+
let(:clazz) { Object.const_get(test_message.type_info) }
|
15
|
+
let(:payload) { clazz.parse(payload_str) }
|
16
|
+
|
17
|
+
context 'CREATED' do
|
18
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::CREATED }
|
19
|
+
|
20
|
+
it 'logs everything' do
|
21
|
+
expect(RailsPipeline.logger).to receive(:info).with(test_message.to_s)
|
22
|
+
handler.handle_payload
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'UPDATED' do
|
27
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::UPDATED }
|
28
|
+
it 'logs everything' do
|
29
|
+
expect(RailsPipeline.logger).to receive(:info).with(test_message.to_s)
|
30
|
+
handler.handle_payload
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'DELETED' do
|
35
|
+
let(:event) { RailsPipeline::EncryptedMessage::EventType::DELETED }
|
36
|
+
it 'logs everything' do
|
37
|
+
expect(RailsPipeline.logger).to receive(:info).with(test_message.to_s)
|
38
|
+
handler.handle_payload
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RailsPipeline::IronmqPullingSubscriber do
|
4
|
+
let(:subject){RailsPipeline::IronmqPullingSubscriber.new("test_queue")}
|
5
|
+
let(:failing_proc){Proc.new{false}}
|
6
|
+
let(:successful_proc){Proc.new{true}}
|
7
|
+
|
8
|
+
describe "#start_subscription" do
|
9
|
+
it "should attempt to process a dequeued message" do
|
10
|
+
subject.stub(:pull_message).and_yield("foo")
|
11
|
+
subject.stub(:process_message){subject.deactivate_subscription}
|
12
|
+
subject.start_subscription{}
|
13
|
+
expect(subject).to have_received(:process_message)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#process_message" do
|
18
|
+
context "when receiving a nil message" do
|
19
|
+
it "deactivates the current subscription" do
|
20
|
+
subject.process_message(nil, true, successful_proc)
|
21
|
+
expect(subject.active_subscription?).to eql false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when receiving a non-nil message" do
|
26
|
+
context "when an issue occurs while generating an message envelope" do
|
27
|
+
let(:malformed_message){double("message", :body => "a malformed message",
|
28
|
+
:delete => "a fine deletion implementation")}
|
29
|
+
|
30
|
+
before(:each) do
|
31
|
+
subject.activate_subscription
|
32
|
+
expect {subject.process_message(malformed_message, true, successful_proc)}.to raise_error
|
33
|
+
end
|
34
|
+
|
35
|
+
it "does not delete the message" do
|
36
|
+
expect(malformed_message).to_not have_received(:delete)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "deactivates the subscription" do
|
40
|
+
expect(subject.active_subscription?).to eql false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#process_envelope" do
|
47
|
+
let(:failing_proc){Proc.new{false}}
|
48
|
+
let(:successful_proc){Proc.new{true}}
|
49
|
+
let(:test_envelope){double("envelope")}
|
50
|
+
let(:message){double("message", :delete => "a deletion implementation")}
|
51
|
+
|
52
|
+
context "when the block passed returns true" do
|
53
|
+
it "deletes the passed message" do
|
54
|
+
subject.process_envelope(test_envelope, message, successful_proc)
|
55
|
+
expect(message).to have_received(:delete)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when the block passeed returns false" do
|
60
|
+
it "does not delete the passed message" do
|
61
|
+
subject.process_envelope(test_envelope, message, failing_proc)
|
62
|
+
expect(message).to_not have_received(:delete)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#active_subscription?" do
|
68
|
+
context "when the subscriber is currently active" do
|
69
|
+
it "returns true" do
|
70
|
+
subject.activate_subscription
|
71
|
+
expect(subject.active_subscription?).to eq true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context "when the subscriber is not currently active" do
|
76
|
+
it "returns false" do
|
77
|
+
subject.deactivate_subscription
|
78
|
+
expect(subject.active_subscription?).to eq false
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "activate_subscription" do
|
84
|
+
it "sets the subscription status of the subscriber to true" do
|
85
|
+
subject.deactivate_subscription
|
86
|
+
subject.activate_subscription
|
87
|
+
expect(subject.active_subscription?).to eql true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "deactivate_subscription" do
|
92
|
+
it "sets the subscription status of the subscriber to false" do
|
93
|
+
subject.activate_subscription
|
94
|
+
subject.deactivate_subscription
|
95
|
+
expect(subject.active_subscription?).to eql false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|