rails-pipeline 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|