spec/unit/models/presence_message_spec.rb in ably-0.8.15 vs spec/unit/models/presence_message_spec.rb in ably-1.0.0
- old
+ new
@@ -381,6 +381,198 @@
expect(subject.assigned_to_protocol_message?).to eql(true)
end
end
end
end
+
+
+ context '#from_encoded (#TP4)' do
+ context 'with no encoding' do
+ let(:message_data) do
+ { action: 2, data: 'data-string' }
+ end
+ let(:from_encoded) { subject.from_encoded(message_data) }
+
+ it 'returns a presence message object' do
+ expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
+ expect(from_encoded.action).to eq(:enter)
+ expect(from_encoded.data).to eql('data-string')
+ expect(from_encoded.encoding).to be_nil
+ end
+
+ context 'with a block' do
+ it 'does not call the block' do
+ block_called = false
+ subject.from_encoded(message_data) do |exception, message|
+ block_called = true
+ end
+ expect(block_called).to be_falsey
+ end
+ end
+ end
+
+ context 'with an encoding' do
+ let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
+ let(:message_data) do
+ { action: 'leave', data: JSON.dump(hash_data), encoding: 'json' }
+ end
+ let(:from_encoded) { subject.from_encoded(message_data) }
+
+ it 'returns a presence message object' do
+ expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
+ expect(from_encoded.action).to eq(:leave)
+ expect(from_encoded.data).to eql(hash_data)
+ expect(from_encoded.encoding).to be_nil
+ end
+ end
+
+ context 'with a custom encoding' do
+ let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
+ let(:message_data) do
+ { action: 1, data: JSON.dump(hash_data), encoding: 'foo/json' }
+ end
+ let(:from_encoded) { subject.from_encoded(message_data) }
+
+ it 'returns a presence message object with the residual incompatible transforms left in the encoding property' do
+ expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
+ expect(from_encoded.action).to eq(1)
+ expect(from_encoded.data).to eql(hash_data)
+ expect(from_encoded.encoding).to eql('foo')
+ end
+ end
+
+ context 'with a Cipher encoding' do
+ let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
+ let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
+ let(:crypto) { Ably::Util::Crypto.new(cipher_params) }
+ let(:payload) { random_str }
+ let(:message_data) do
+ { action: 1, data: crypto.encrypt(payload), encoding: 'utf-8/cipher+aes-128-cbc' }
+ end
+ let(:channel_options) { { cipher: cipher_params } }
+ let(:from_encoded) { subject.from_encoded(message_data, channel_options) }
+
+ it 'returns a presence message object with the residual incompatible transforms left in the encoding property' do
+ expect(from_encoded).to be_a(Ably::Models::PresenceMessage)
+ expect(from_encoded.data).to eql(payload)
+ expect(from_encoded.encoding).to be_nil
+ end
+ end
+
+ context 'with invalid Cipher encoding' do
+ let(:hash_data) { { 'key' => 'value', 'key2' => 123 } }
+ let(:cipher_params) { { key: Ably::Util::Crypto.generate_random_key(128), algorithm: 'aes', mode: 'cbc', key_length: 128 } }
+ let(:unencryped_payload) { random_str }
+ let(:message_data) do
+ { action: 1, data: unencryped_payload, encoding: 'utf-8/cipher+aes-128-cbc' }
+ end
+ let(:channel_options) { { cipher: cipher_params } }
+
+ context 'without a block' do
+ it 'raises an exception' do
+ expect { subject.from_encoded(message_data, channel_options) }.to raise_exception(Ably::Exceptions::CipherError)
+ end
+ end
+
+ context 'with a block' do
+ it 'calls the block with the exception' do
+ block_called = false
+ subject.from_encoded(message_data, channel_options) do |exception, message|
+ expect(exception).to be_a(Ably::Exceptions::CipherError)
+ block_called = true
+ end
+ expect(block_called).to be_truthy
+ end
+ end
+ end
+ end
+
+ context '#from_encoded_array (#TP4)' do
+ context 'with no encoding' do
+ let(:message_data) do
+ [{ action: 1, data: 'data-string' }, { action: 2, data: 'data-string' }]
+ end
+ let(:from_encoded) { subject.from_encoded_array(message_data) }
+
+ it 'returns an Array of presence message objects' do
+ first = from_encoded.first
+ expect(first).to be_a(Ably::Models::PresenceMessage)
+ expect(first.action).to eq(1)
+ expect(first.data).to eql('data-string')
+ expect(first.encoding).to be_nil
+ last = from_encoded.last
+ expect(last.action).to eq(:enter)
+ end
+ end
+ end
+
+ context '#shallow_clone' do
+ context 'with inherited attributes from ProtocolMessage' do
+ let(:protocol_message) {
+ Ably::Models::ProtocolMessage.new('id' => 'fooId', 'connectionId' => protocol_connection_id, 'action' => 1, 'timestamp' => protocol_message_timestamp)
+ }
+ let(:protocol_connection_id) { random_str }
+ let(:model) { subject.new({ 'action' => 2 }, protocol_message: protocol_message) }
+
+ it 'creates a duplicate of the message without any ProtocolMessage dependency' do
+ clone = model.shallow_clone
+ expect(clone.id).to match(/fooId/)
+ expect(clone.connection_id).to eql(protocol_connection_id)
+ expect(as_since_epoch(clone.timestamp)).to eq(protocol_message_timestamp)
+ expect(clone.action).to eq(2)
+ end
+ end
+
+ context 'with embedded attributes for all fields' do
+ let(:message_timestamp) { as_since_epoch(Time.now) + 100 }
+ let(:connection_id) { random_str }
+ let(:model) { subject.new({ 'action' => 3, 'id' => 'fooId', 'connectionId' => connection_id, 'timestamp' => message_timestamp }) }
+
+ it 'creates a duplicate of the message without any ProtocolMessage dependency' do
+ clone = model.shallow_clone
+ expect(clone.id).to eql('fooId')
+ expect(clone.connection_id).to eql(connection_id)
+ expect(as_since_epoch(clone.timestamp)).to eq(message_timestamp)
+ expect(clone.action).to eq(3)
+ end
+ end
+
+ context 'with new attributes passed in to the method' do
+ let(:protocol_message) {
+ Ably::Models::ProtocolMessage.new('id' => 'fooId', 'connectionId' => protocol_connection_id, 'action' => 1, 'timestamp' => protocol_message_timestamp)
+ }
+ let(:protocol_connection_id) { random_str }
+ let(:model) { subject.new({ 'action' => 2 }, protocol_message: protocol_message) }
+
+ it 'creates a duplicate of the message without any ProtocolMessage dependency' do
+ clone = model.shallow_clone(id: 'newId', action: 1, timestamp: protocol_message_timestamp + 1000)
+ expect(clone.id).to match(/newId/)
+ expect(clone.connection_id).to eql(protocol_connection_id)
+ expect(as_since_epoch(clone.timestamp)).to eq(protocol_message_timestamp + 1000)
+ expect(clone.action).to eq(1)
+ end
+
+ context 'with an invalid ProtocolMessage (missing an ID)' do
+ let(:protocol_message) {
+ Ably::Models::ProtocolMessage.new('connectionId' => protocol_connection_id, 'action' => 1, 'timestamp' => protocol_message_timestamp)
+ }
+ it 'allows an ID to be passed in to the shallow clone that takes precedence' do
+ clone = model.shallow_clone(id: 'newId', action: 1, timestamp: protocol_message_timestamp + 1000)
+ expect(clone.id).to match(/newId/)
+ end
+ end
+
+ context 'with mixing of cases' do
+ it 'resolves case issues and can use camelCase or snake_case' do
+ clone = model.shallow_clone(connectionId: 'camelCaseSym')
+ expect(clone.connection_id).to match(/camelCaseSym/)
+
+ clone = model.shallow_clone('connectionId' => 'camelCaseStr')
+ expect(clone.connection_id).to match(/camelCaseStr/)
+
+ clone = model.shallow_clone(connection_id: 'snake_case_sym')
+ expect(clone.connection_id).to match(/snake_case_sym/)
+ end
+ end
+ end
+ end
end