ably 1.1.6 → 1.1.7

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/check.yml +15 -1
  3. data/CHANGELOG.md +26 -0
  4. data/README.md +14 -2
  5. data/ably.gemspec +11 -6
  6. data/lib/ably.rb +1 -0
  7. data/lib/ably/agent.rb +3 -0
  8. data/lib/ably/exceptions.rb +6 -0
  9. data/lib/ably/models/connection_details.rb +2 -0
  10. data/lib/ably/models/message.rb +14 -0
  11. data/lib/ably/models/presence_message.rb +14 -0
  12. data/lib/ably/models/protocol_message.rb +8 -0
  13. data/lib/ably/realtime/channel/channel_manager.rb +2 -2
  14. data/lib/ably/realtime/channel/publisher.rb +5 -0
  15. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +14 -6
  16. data/lib/ably/realtime/connection.rb +5 -2
  17. data/lib/ably/rest/channel.rb +8 -1
  18. data/lib/ably/rest/client.rb +11 -11
  19. data/lib/ably/version.rb +1 -13
  20. data/spec/acceptance/realtime/auth_spec.rb +1 -1
  21. data/spec/acceptance/realtime/channel_history_spec.rb +25 -0
  22. data/spec/acceptance/realtime/channel_spec.rb +14 -0
  23. data/spec/acceptance/realtime/connection_failures_spec.rb +3 -1
  24. data/spec/acceptance/realtime/connection_spec.rb +6 -27
  25. data/spec/acceptance/realtime/presence_history_spec.rb +3 -1
  26. data/spec/acceptance/realtime/presence_spec.rb +13 -158
  27. data/spec/acceptance/rest/channel_spec.rb +13 -0
  28. data/spec/acceptance/rest/client_spec.rb +23 -19
  29. data/spec/shared/model_behaviour.rb +1 -1
  30. data/spec/spec_helper.rb +11 -2
  31. data/spec/unit/models/message_spec.rb +59 -0
  32. data/spec/unit/models/presence_message_spec.rb +49 -0
  33. data/spec/unit/models/protocol_message_spec.rb +48 -0
  34. data/spec/unit/realtime/channel_spec.rb +1 -1
  35. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +38 -0
  36. data/spec/unit/rest/channel_spec.rb +10 -0
  37. data/spec/unit/rest/client_spec.rb +20 -0
  38. metadata +36 -21
@@ -183,6 +183,31 @@ describe Ably::Realtime::Channel, '#history', :event_machine do
183
183
  end
184
184
  end
185
185
 
186
+ context 'when channel receives update event after an attachment' do
187
+ before do
188
+ channel.on(:attached) do
189
+ channel.publish(event, message_after_attach) do
190
+ subsequent_serial = channel.properties.attach_serial.dup.tap { |serial| serial[-1] = '1' }
191
+ attached_message = Ably::Models::ProtocolMessage.new(action: 11, channel: channel_name, flags: 0, channel_serial: subsequent_serial)
192
+ client.connection.__incoming_protocol_msgbus__.publish :protocol_message, attached_message
193
+ end
194
+ end
195
+ end
196
+
197
+ it 'updates attach_serial' do
198
+ rest_channel.publish event, message_before_attach
199
+
200
+ channel.on(:update) do
201
+ channel.history(until_attach: true) do |messages|
202
+ expect(messages.items.count).to eql(2)
203
+ stop_reactor
204
+ end
205
+ end
206
+
207
+ channel.attach
208
+ end
209
+ end
210
+
186
211
  context 'and two pages of messages' do
187
212
  it 'retrieves two pages of messages before channel was attached' do
188
213
  10.times { rest_channel.publish event, message_before_attach }
@@ -1403,6 +1403,20 @@ describe Ably::Realtime::Channel, :event_machine do
1403
1403
  end
1404
1404
  end
1405
1405
  end
1406
+
1407
+ context 'message size exceeded (#TO3l8)' do
1408
+ let(:message) { 'x' * 700000 }
1409
+
1410
+ let(:client) { auto_close Ably::Realtime::Client.new(client_options) }
1411
+ let(:channel) { client.channels.get(channel_name) }
1412
+
1413
+ it 'should not allow to send a message' do
1414
+ channel.publish('event', message).errback do |error|
1415
+ expect(error).to be_instance_of(Ably::Exceptions::MaxMessageSizeExceeded)
1416
+ stop_reactor
1417
+ end
1418
+ end
1419
+ end
1406
1420
  end
1407
1421
 
1408
1422
  describe '#subscribe' do
@@ -1320,7 +1320,9 @@ describe Ably::Realtime::Connection, 'failures', :event_machine do
1320
1320
  end)
1321
1321
  end
1322
1322
 
1323
- it 'triggers a re-authentication and then resumes the connection' do
1323
+ xit 'triggers a re-authentication and then resumes the connection' do
1324
+ # [PENDING] After sandbox env update connection isn't found and a new connection is created. Spec fails
1325
+ #
1324
1326
  connection.once(:connected) do
1325
1327
  connection_id = connection.id
1326
1328
 
@@ -1454,7 +1454,7 @@ describe Ably::Realtime::Connection, :event_machine do
1454
1454
  let(:client_options) { default_options.merge(tls: true) }
1455
1455
 
1456
1456
  it 'uses TLS for the Internet check to https://internet-up.ably-realtime.com/is-the-internet-up.txt' do
1457
- expect(EventMachine::HttpRequest).to receive(:new).with('https://internet-up.ably-realtime.com/is-the-internet-up.txt').and_return(http_request)
1457
+ expect(EventMachine::HttpRequest).to receive(:new).with('https://internet-up.ably-realtime.com/is-the-internet-up.txt', { tls: { verify_peer: true } }).and_return(http_request)
1458
1458
  connection.internet_up?
1459
1459
  stop_reactor
1460
1460
  end
@@ -1464,7 +1464,7 @@ describe Ably::Realtime::Connection, :event_machine do
1464
1464
  let(:client_options) { default_options.merge(tls: false, use_token_auth: true) }
1465
1465
 
1466
1466
  it 'uses TLS for the Internet check to http://internet-up.ably-realtime.com/is-the-internet-up.txt' do
1467
- expect(EventMachine::HttpRequest).to receive(:new).with('http://internet-up.ably-realtime.com/is-the-internet-up.txt').and_return(http_request)
1467
+ expect(EventMachine::HttpRequest).to receive(:new).with('http://internet-up.ably-realtime.com/is-the-internet-up.txt', { tls: { verify_peer: true } }).and_return(http_request)
1468
1468
  connection.internet_up?
1469
1469
  stop_reactor
1470
1470
  end
@@ -1478,7 +1478,7 @@ describe Ably::Realtime::Connection, :event_machine do
1478
1478
  let(:client_options) { default_options.merge(tls: true) }
1479
1479
 
1480
1480
  it 'checks the Internet up URL over TLS' do
1481
- expect(EventMachine::HttpRequest).to receive(:new).with("https:#{Ably::INTERNET_CHECK.fetch(:url)}").and_return(double('request', get: EventMachine::DefaultDeferrable.new))
1481
+ expect(EventMachine::HttpRequest).to receive(:new).with("https:#{Ably::INTERNET_CHECK.fetch(:url)}", { tls: { verify_peer: true } }).and_return(double('request', get: EventMachine::DefaultDeferrable.new))
1482
1482
  connection.internet_up?
1483
1483
  stop_reactor
1484
1484
  end
@@ -1488,7 +1488,7 @@ describe Ably::Realtime::Connection, :event_machine do
1488
1488
  let(:client_options) { default_options.merge(tls: false, use_token_auth: true) }
1489
1489
 
1490
1490
  it 'checks the Internet up URL over TLS' do
1491
- expect(EventMachine::HttpRequest).to receive(:new).with("http:#{Ably::INTERNET_CHECK.fetch(:url)}").and_return(double('request', get: EventMachine::DefaultDeferrable.new))
1491
+ expect(EventMachine::HttpRequest).to receive(:new).with("http:#{Ably::INTERNET_CHECK.fetch(:url)}", { tls: { verify_peer: true } }).and_return(double('request', get: EventMachine::DefaultDeferrable.new))
1492
1492
  connection.internet_up?
1493
1493
  stop_reactor
1494
1494
  end
@@ -1840,35 +1840,14 @@ describe Ably::Realtime::Connection, :event_machine do
1840
1840
  client
1841
1841
  end
1842
1842
 
1843
- it 'sends the lib version param lib (#RTN2g)' do
1843
+ it 'sends the lib version param agent (#RCS7d)' do
1844
1844
  expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
1845
1845
  uri = URI.parse(url)
1846
- expect(CGI::parse(uri.query)['lib'][0]).to match(/^ruby-1\.1\.\d+(-[\w\.]+)?+$/)
1846
+ expect(CGI::parse(uri.query)['agent'][0]).to match(/^ably-ruby\/\d\.\d\.\d ruby\/\d\.\d\.\d$/)
1847
1847
  stop_reactor
1848
1848
  end
1849
1849
  client
1850
1850
  end
1851
-
1852
- context 'with variant' do
1853
- let(:variant) { 'foo' }
1854
-
1855
- before do
1856
- Ably.lib_variant = variant
1857
- end
1858
-
1859
- after do
1860
- Ably.lib_variant = nil
1861
- end
1862
-
1863
- it 'sends the lib version param lib with the variant (#RTN2g + #RSC7b)' do
1864
- expect(EventMachine).to receive(:connect) do |host, port, transport, object, url|
1865
- uri = URI.parse(url)
1866
- expect(CGI::parse(uri.query)['lib'][0]).to match(/^ruby-#{variant}-1\.1\.\d+(-[\w\.]+)?$/)
1867
- stop_reactor
1868
- end
1869
- client
1870
- end
1871
- end
1872
1851
  end
1873
1852
 
1874
1853
  context 'transport_params (#RTC1f)' do
@@ -20,7 +20,7 @@ describe Ably::Realtime::Presence, 'history', :event_machine do
20
20
 
21
21
  it 'provides up to the moment presence history' do
22
22
  presence_client_one.enter(data) do
23
- presence_client_one.leave(leave_data) do
23
+ presence_client_one.subscribe(:leave) do
24
24
  presence_client_one.history do |history_page|
25
25
  expect(history_page).to be_a(Ably::Models::PaginatedResult)
26
26
  expect(history_page.items.count).to eql(2)
@@ -36,6 +36,8 @@ describe Ably::Realtime::Presence, 'history', :event_machine do
36
36
  stop_reactor
37
37
  end
38
38
  end
39
+
40
+ presence_client_one.leave(leave_data)
39
41
  end
40
42
  end
41
43
 
@@ -498,7 +498,9 @@ describe Ably::Realtime::Presence, :event_machine do
498
498
  end
499
499
 
500
500
  presence_client_one.enter do
501
- presence_client_one.leave
501
+ EventMachine.add_timer(0.5) do
502
+ presence_client_one.leave
503
+ end
502
504
  end
503
505
  end
504
506
  end
@@ -705,7 +707,7 @@ describe Ably::Realtime::Presence, :event_machine do
705
707
 
706
708
  context '#sync_complete? and SYNC flags (#RTP1)' do
707
709
  context 'when attaching to a channel without any members present' do
708
- it 'sync_complete? is true, there is no presence flag, and the presence channel is considered synced immediately (#RTP1)' do
710
+ xit 'sync_complete? is true, there is no presence flag, and the presence channel is considered synced immediately (#RTP1)' do
709
711
  flag_checked = false
710
712
 
711
713
  anonymous_client.connection.__incoming_protocol_msgbus__.subscribe(:protocol_message) do |protocol_message|
@@ -1211,10 +1213,11 @@ describe Ably::Realtime::Presence, :event_machine do
1211
1213
  channel_client_one.attach do
1212
1214
  presence_client_one.subscribe(:enter) do
1213
1215
  presence_client_one.unsubscribe :enter
1214
-
1215
- expect(presence_client_one.members).to be_in_sync
1216
- expect(presence_client_one.members.send(:members).count).to eql(1)
1217
- presence_client_one.leave data
1216
+ EventMachine.add_timer(0.5) do
1217
+ expect(presence_client_one.members).to be_in_sync
1218
+ expect(presence_client_one.members.send(:members).count).to eql(1)
1219
+ presence_client_one.leave data
1220
+ end
1218
1221
  end
1219
1222
 
1220
1223
  presence_client_one.enter(enter_data) do
@@ -2137,16 +2140,18 @@ describe Ably::Realtime::Presence, :event_machine do
2137
2140
  end
2138
2141
 
2139
2142
  it 'emits an error when cipher does not match and presence data cannot be decoded' do
2140
- incompatible_encrypted_channel.attach do
2143
+ incompatible_encrypted_channel.once(:attached) do
2141
2144
  expect(client_two.logger).to receive(:error) do |*args, &block|
2142
2145
  expect(args.concat([block ? block.call : nil]).join(',')).to match(/Cipher algorithm AES-128-CBC does not match/)
2143
2146
  stop_reactor
2144
- end
2147
+ end.at_least(:once)
2145
2148
 
2146
2149
  encrypted_channel.attach do
2147
2150
  encrypted_channel.presence.enter data
2148
2151
  end
2149
2152
  end
2153
+
2154
+ incompatible_encrypted_channel.attach
2150
2155
  end
2151
2156
  end
2152
2157
  end
@@ -2522,156 +2527,6 @@ describe Ably::Realtime::Presence, :event_machine do
2522
2527
  client_one.connection.transport.__outgoing_protocol_msgbus__.unsubscribe
2523
2528
  end
2524
2529
 
2525
- context 'and the resume flag is true' do
2526
- context 'and the presence flag is false' do
2527
- it 'does not send any presence events as the PresenceMap is in sync (#RTP5c1)' do
2528
- presence_client_one.enter
2529
- presence_client_one.subscribe(:enter) do
2530
- presence_client_one.unsubscribe :enter
2531
-
2532
- client_one.connection.transport.__outgoing_protocol_msgbus__.subscribe do |message|
2533
- raise "No presence state updates to Ably are expected. Message sent: #{message.to_json}" if client_one.connection.connected?
2534
- end
2535
-
2536
- cripple_websocket_transport
2537
-
2538
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2539
- action: attached_action,
2540
- channel: channel_name,
2541
- flags: resume_flag
2542
- )
2543
-
2544
- EventMachine.add_timer(1) do
2545
- presence_client_one.get do |members|
2546
- expect(members.length).to eql(1)
2547
- expect(presence_client_one.members.local_members.length).to eql(1)
2548
- stop_reactor
2549
- end
2550
- end
2551
- end
2552
- end
2553
- end
2554
-
2555
- context 'and the presence flag is true' do
2556
- context 'and following the SYNC all local MemberMap members are present in the PresenceMap' do
2557
- it 'does nothing as MemberMap is in sync (#RTP5c2)' do
2558
- presence_client_one.enter
2559
- presence_client_one.subscribe(:enter) do
2560
- presence_client_one.unsubscribe :enter
2561
-
2562
- expect(presence_client_one.members.length).to eql(1)
2563
- expect(presence_client_one.members.local_members.length).to eql(1)
2564
-
2565
- presence_client_one.members.once(:in_sync) do
2566
- presence_client_one.get do |members|
2567
- expect(members.length).to eql(1)
2568
- expect(presence_client_one.members.local_members.length).to eql(1)
2569
- stop_reactor
2570
- end
2571
- end
2572
-
2573
- client_one.connection.transport.__outgoing_protocol_msgbus__.subscribe do |message|
2574
- raise "No presence state updates to Ably are expected. Message sent: #{message.to_json}" if client_one.connection.connected?
2575
- end
2576
-
2577
- cripple_websocket_transport
2578
-
2579
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2580
- action: attached_action,
2581
- channel: channel_name,
2582
- flags: resume_flag + presence_flag
2583
- )
2584
-
2585
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2586
- action: sync_action,
2587
- channel: channel_name,
2588
- presence: presence_client_one.members.map(&:shallow_clone).map(&:as_json),
2589
- channelSerial: nil # no further SYNC messages expected
2590
- )
2591
- end
2592
- end
2593
- end
2594
-
2595
- context 'and following the SYNC a local MemberMap member is not present in the PresenceMap' do
2596
- it 're-enters the missing members automatically (#RTP5c2)' do
2597
- sync_check_completed = false
2598
-
2599
- presence_client_one.enter
2600
- presence_client_one.subscribe(:enter) do
2601
- presence_client_one.unsubscribe :enter
2602
-
2603
- expect(presence_client_one.members.length).to eql(1)
2604
- expect(presence_client_one.members.local_members.length).to eql(1)
2605
-
2606
- client_one.connection.__outgoing_protocol_msgbus__.subscribe(:protocol_message) do |message|
2607
- next if message.action == :close # ignore finalization of connection
2608
-
2609
- expect(message.action).to eq(:presence)
2610
- presence_message = message.presence.first
2611
- expect(presence_message.action).to eq(:enter)
2612
- expect(presence_message.client_id).to eq(client_one.auth.client_id)
2613
-
2614
- presence_client_one.subscribe(:enter) do |message|
2615
- expect(message.connection_id).to eql(client_one.connection.id)
2616
- expect(message.client_id).to eq(client_one.auth.client_id)
2617
-
2618
- EventMachine.next_tick do
2619
- expect(presence_client_one.members.length).to eql(2)
2620
- expect(presence_client_one.members.local_members.length).to eql(1)
2621
- expect(sync_check_completed).to be_truthy
2622
- stop_reactor
2623
- end
2624
- end
2625
-
2626
- # Fabricate Ably sending back the Enter PresenceMessage to the client a short while after
2627
- # ensuring the PresenceMap for a short period does not have this member as to be expected in reality
2628
- EventMachine.add_timer(0.2) do
2629
- connection_id = random_str
2630
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2631
- action: presence_action,
2632
- channel: channel_name,
2633
- connectionId: client_one.connection.id,
2634
- connectionSerial: 50,
2635
- timestamp: as_since_epoch(Time.now),
2636
- presence: [presence_message.shallow_clone(id: "#{client_one.connection.id}:0:0", timestamp: as_since_epoch(Time.now)).as_json]
2637
- )
2638
- end
2639
- end
2640
-
2641
- presence_client_one.members.once(:in_sync) do
2642
- # For a brief period, the client will have re-entered the missing members from the local_members
2643
- # but the enter from Ably will have not been received, so at this point the local_members will be empty
2644
- presence_client_one.get do |members|
2645
- expect(members.length).to eql(1)
2646
- expect(members.first.connection_id).to_not eql(client_one.connection.id)
2647
- expect(presence_client_one.members.local_members.length).to eql(0)
2648
- sync_check_completed = true
2649
- end
2650
- end
2651
-
2652
- cripple_websocket_transport
2653
-
2654
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2655
- action: attached_action,
2656
- channel: channel_name,
2657
- flags: resume_flag + presence_flag
2658
- )
2659
-
2660
- # Complete the SYNC but without the member who was entered by this client
2661
- connection_id = random_str
2662
- fabricate_incoming_protocol_message Ably::Models::ProtocolMessage.new(
2663
- action: sync_action,
2664
- channel: channel_name,
2665
- timestamp: as_since_epoch(Time.now),
2666
- presence: [{ id: "#{connection_id}:0:0", action: present_action, connection_id: connection_id, client_id: random_str }],
2667
- chanenlSerial: nil # no further SYNC messages expected
2668
- )
2669
- end
2670
- end
2671
- end
2672
- end
2673
- end
2674
-
2675
2530
  context 'and the resume flag is false' do
2676
2531
  context 'and the presence flag is false' do
2677
2532
  let(:member_data) { random_str }
@@ -60,6 +60,8 @@ describe Ably::Rest::Channel do
60
60
  end
61
61
 
62
62
  it 'publishes an array of messages in one HTTP request' do
63
+ expect(messages.sum(&:size) < Ably::Rest::Channel::MAX_MESSAGE_SIZE).to eq(true)
64
+
63
65
  expect(client).to receive(:post).once.and_call_original
64
66
  expect(channel.publish(messages)).to eql(true)
65
67
  expect(channel.history.items.map(&:name)).to match_array(messages.map { |message| message[:name] })
@@ -75,6 +77,8 @@ describe Ably::Rest::Channel do
75
77
  end
76
78
 
77
79
  it 'publishes an array of messages in one HTTP request' do
80
+ expect(messages.sum(&:size) < Ably::Rest::Channel::MAX_MESSAGE_SIZE).to eq(true)
81
+
78
82
  expect(client).to receive(:post).once.and_call_original
79
83
  expect(channel.publish(messages)).to eql(true)
80
84
  expect(channel.history.items.map(&:name)).to match_array(messages.map(&:name))
@@ -350,6 +354,15 @@ describe Ably::Rest::Channel do
350
354
  end
351
355
  end
352
356
  end
357
+
358
+ context 'message size is exceeded (#TO3l8)' do
359
+ let(:data) { 101.times.map { { data: 'x' * 655 } } }
360
+
361
+ it 'should raise Ably::Exceptions::MaxMessageSizeExceeded exception' do
362
+ expect { channel.publish([ data: data ]) }.to \
363
+ raise_error(Ably::Exceptions::MaxMessageSizeExceeded)
364
+ end
365
+ end
353
366
  end
354
367
 
355
368
  describe '#history' do
@@ -1081,29 +1081,15 @@ describe Ably::Rest::Client do
1081
1081
  end
1082
1082
 
1083
1083
  context 'version headers', :webmock do
1084
- [nil, 'foo'].each do |variant|
1085
- context "with variant #{variant ? variant : 'none'}" do
1086
- if variant
1087
- before do
1088
- Ably.lib_variant = variant
1089
- end
1084
+ [nil, 'ably-ruby/1.1.1 ruby/1.9.3'].each do |agent|
1085
+ context "with #{agent ? "custom #{agent}" : 'default'} agent" do
1086
+ let(:client_options) { default_options.merge(key: api_key, agent: agent) }
1090
1087
 
1091
- after do
1092
- Ably.lib_variant = nil
1093
- end
1094
- end
1095
-
1096
- let(:client_options) { default_options.merge(key: api_key) }
1097
1088
  let!(:publish_message_stub) do
1098
- lib = ['ruby']
1099
- lib << variant if variant
1100
- lib << Ably::VERSION
1101
-
1102
-
1103
1089
  stub_request(:post, "#{client.endpoint}/channels/foo/publish").
1104
1090
  with(headers: {
1105
1091
  'X-Ably-Version' => Ably::PROTOCOL_VERSION,
1106
- 'X-Ably-Lib' => lib.join('-')
1092
+ 'Ably-Agent' => agent || Ably::AGENT
1107
1093
  }).
1108
1094
  to_return(status: 201, body: '{}', headers: { 'Content-Type' => 'application/json' })
1109
1095
  end
@@ -1117,7 +1103,7 @@ describe Ably::Rest::Client do
1117
1103
  end
1118
1104
  end
1119
1105
 
1120
- context '#request (#RSC19*)' do
1106
+ context '#request (#RSC19*, #TO3l9)' do
1121
1107
  let(:client_options) { default_options.merge(key: api_key) }
1122
1108
  let(:device_id) { random_str }
1123
1109
  let(:endpoint) { client.endpoint }
@@ -1172,6 +1158,12 @@ describe Ably::Rest::Client do
1172
1158
 
1173
1159
  expect(response).to be_success
1174
1160
  end
1161
+
1162
+ it 'raises an exception once body size in bytes exceeded' do
1163
+ expect {
1164
+ client.request(:post, endpoint, {}, { content: 'x' * Ably::Rest::Client::MAX_FRAME_SIZE })
1165
+ }.to raise_error(Ably::Exceptions::MaxFrameSizeExceeded)
1166
+ end
1175
1167
  end
1176
1168
 
1177
1169
  context 'delete', :webmock do
@@ -1201,6 +1193,12 @@ describe Ably::Rest::Client do
1201
1193
 
1202
1194
  expect(response).to be_success
1203
1195
  end
1196
+
1197
+ it 'raises an exception once body size in bytes exceeded' do
1198
+ expect {
1199
+ client.request(:patch, endpoint, {}, { content: 'x' * Ably::Rest::Client::MAX_FRAME_SIZE })
1200
+ }.to raise_error(Ably::Exceptions::MaxFrameSizeExceeded)
1201
+ end
1204
1202
  end
1205
1203
 
1206
1204
  context 'put', :webmock do
@@ -1224,6 +1222,12 @@ describe Ably::Rest::Client do
1224
1222
 
1225
1223
  expect(response).to be_success
1226
1224
  end
1225
+
1226
+ it 'raises an exception once body size in bytes exceeded' do
1227
+ expect {
1228
+ client.request(:put, endpoint, {}, { content: 'x' * Ably::Rest::Client::MAX_FRAME_SIZE })
1229
+ }.to raise_error(Ably::Exceptions::MaxFrameSizeExceeded)
1230
+ end
1227
1231
  end
1228
1232
  end
1229
1233