ably-rest 0.7.1 → 0.7.3

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 (148) hide show
  1. checksums.yaml +13 -5
  2. data/.gitmodules +1 -1
  3. data/.rspec +1 -0
  4. data/.travis.yml +7 -3
  5. data/SPEC.md +495 -419
  6. data/ably-rest.gemspec +19 -5
  7. data/lib/ably-rest.rb +9 -1
  8. data/lib/submodules/ably-ruby/.gitignore +6 -0
  9. data/lib/submodules/ably-ruby/.rspec +1 -0
  10. data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
  11. data/lib/submodules/ably-ruby/.travis.yml +10 -0
  12. data/lib/submodules/ably-ruby/Gemfile +4 -0
  13. data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
  14. data/lib/submodules/ably-ruby/README.md +122 -0
  15. data/lib/submodules/ably-ruby/Rakefile +34 -0
  16. data/lib/submodules/ably-ruby/SPEC.md +1794 -0
  17. data/lib/submodules/ably-ruby/ably.gemspec +36 -0
  18. data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
  19. data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
  20. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
  21. data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
  22. data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
  23. data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
  24. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
  25. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
  26. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
  27. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
  28. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
  29. data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
  30. data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
  31. data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
  32. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
  33. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
  34. data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
  35. data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
  36. data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
  37. data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
  38. data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
  39. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
  40. data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
  41. data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
  42. data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
  43. data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
  44. data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
  45. data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
  46. data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
  47. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
  48. data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
  49. data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  50. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
  51. data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
  52. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
  53. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
  54. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
  55. data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
  56. data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
  57. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
  58. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
  59. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
  60. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
  61. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
  62. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
  63. data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
  64. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
  65. data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
  66. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
  67. data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
  68. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
  69. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
  70. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
  71. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
  72. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
  73. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
  74. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
  75. data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
  76. data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
  77. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
  78. data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
  79. data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
  80. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
  81. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
  82. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
  83. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
  84. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
  85. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
  86. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
  87. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
  88. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
  89. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
  90. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
  91. data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
  92. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
  93. data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
  94. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
  95. data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
  96. data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
  97. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
  98. data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
  99. data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
  100. data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
  101. data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
  102. data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
  103. data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
  104. data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
  105. data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
  106. data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
  107. data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
  108. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
  109. data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
  110. data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
  111. data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
  112. data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
  113. data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
  114. data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
  115. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
  116. data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
  117. data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
  118. data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
  119. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
  120. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
  121. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
  122. data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
  123. data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
  124. data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
  125. data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
  126. data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
  127. data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
  128. data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
  129. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
  130. data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
  131. data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
  132. data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
  133. data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
  134. data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
  135. data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
  136. data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
  137. data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
  138. data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
  139. data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
  140. data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
  141. data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
  142. data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
  143. data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
  144. data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
  145. data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
  146. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
  147. data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
  148. metadata +182 -27
@@ -0,0 +1,113 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+ require 'shared/model_behaviour'
4
+
5
+ describe Ably::Models::Stat do
6
+ include Ably::Modules::Conversions
7
+
8
+ subject { Ably::Models::Stat }
9
+
10
+ it_behaves_like 'a model', with_simple_attributes: %w(interval_id all inbound outbound persisted connections channels api_requests token_requests) do
11
+ let(:model_args) { [] }
12
+ end
13
+
14
+ describe '#interval_granularity' do
15
+ subject { Ably::Models::Stat.new(interval_id: '2004-02') }
16
+
17
+ it 'returns the granularity of the interval_id' do
18
+ expect(subject.interval_granularity).to eq(:month)
19
+ end
20
+ end
21
+
22
+ describe '#interval_time' do
23
+ subject { Ably::Models::Stat.new(interval_id: '2004-02-01:05:06') }
24
+
25
+ it 'returns a Time object representing the start of the interval' do
26
+ expect(subject.interval_time.to_i).to eql(Time.new(2004, 02, 01, 05, 06, 00, '+00:00').to_i)
27
+ end
28
+ end
29
+
30
+ context 'class methods' do
31
+ describe '#to_interval_id' do
32
+ context 'when time zone of time argument is UTC' do
33
+ it 'converts time 2014-02-03:05:06 with granularity :month into 2014-02' do
34
+ expect(subject.to_interval_id(Time.new(2014, 2, 1, 0, 0, 0, '+00:00'), :month)).to eql('2014-02')
35
+ end
36
+
37
+ it 'converts time 2014-02-03:05:06 with granularity :day into 2014-02-03' do
38
+ expect(subject.to_interval_id(Time.new(2014, 2, 3, 0, 0, 0, '+00:00'), :day)).to eql('2014-02-03')
39
+ end
40
+
41
+ it 'converts time 2014-02-03:05:06 with granularity :hour into 2014-02-03:05' do
42
+ expect(subject.to_interval_id(Time.new(2014, 2, 3, 5, 0, 0, '+00:00'), :hour)).to eql('2014-02-03:05')
43
+ end
44
+
45
+ it 'converts time 2014-02-03:05:06 with granularity :minute into 2014-02-03:05:06' do
46
+ expect(subject.to_interval_id(Time.new(2014, 2, 3, 5, 6, 0, '+00:00'), :minute)).to eql('2014-02-03:05:06')
47
+ end
48
+
49
+ it 'fails with invalid granularity' do
50
+ expect { subject.to_interval_id(Time.now, :invalid) }.to raise_error KeyError
51
+ end
52
+
53
+ it 'fails with invalid time' do
54
+ expect { subject.to_interval_id(nil, :month) }.to raise_error ArgumentError
55
+ end
56
+ end
57
+
58
+ context 'when time zone of time argument is +02:00' do
59
+ it 'converts time 2014-02-03:06 with granularity :hour into 2014-02-03:04 at UTC +00:00' do
60
+ expect(subject.to_interval_id(Time.new(2014, 2, 3, 6, 0, 0, '+02:00'), :hour)).to eql('2014-02-03:04')
61
+ end
62
+ end
63
+ end
64
+
65
+ describe '#from_interval_id' do
66
+ it 'converts a month interval_id 2014-02 into a Time object in UTC 0' do
67
+ expect(subject.from_interval_id('2014-02')).to eql(Time.new(2014, 2))
68
+ expect(subject.from_interval_id('2014-02').utc_offset).to eql(0)
69
+ end
70
+
71
+ it 'converts a day interval_id 2014-02-03 into a Time object in UTC 0' do
72
+ expect(subject.from_interval_id('2014-02-03')).to eql(Time.new(2014, 2, 3))
73
+ expect(subject.from_interval_id('2014-02-03').utc_offset).to eql(0)
74
+ end
75
+
76
+ it 'converts an hour interval_id 2014-02-03:05 into a Time object in UTC 0' do
77
+ expect(subject.from_interval_id('2014-02-03:05')).to eql(Time.new(2014, 2, 3, 5))
78
+ expect(subject.from_interval_id('2014-02-03:05').utc_offset).to eql(0)
79
+ end
80
+
81
+ it 'converts a minute interval_id 2014-02-03:05:06 into a Time object in UTC 0' do
82
+ expect(subject.from_interval_id('2014-02-03:05:06')).to eql(Time.new(2014, 2, 3, 5, 6))
83
+ expect(subject.from_interval_id('2014-02-03:05:06').utc_offset).to eql(0)
84
+ end
85
+
86
+ it 'fails with an invalid interval_id 14-20' do
87
+ expect { subject.from_interval_id('14-20') }.to raise_error ArgumentError
88
+ end
89
+ end
90
+
91
+ describe '#granularity_from_interval_id' do
92
+ it 'returns a :month interval_id for 2014-02' do
93
+ expect(subject.granularity_from_interval_id('2014-02')).to eq(:month)
94
+ end
95
+
96
+ it 'returns a :day interval_id for 2014-02-03' do
97
+ expect(subject.granularity_from_interval_id('2014-02-03')).to eq(:day)
98
+ end
99
+
100
+ it 'returns a :hour interval_id for 2014-02-03:05' do
101
+ expect(subject.granularity_from_interval_id('2014-02-03:05')).to eq(:hour)
102
+ end
103
+
104
+ it 'returns a :minute interval_id for 2014-02-03:05:06' do
105
+ expect(subject.granularity_from_interval_id('2014-02-03:05:06')).to eq(:minute)
106
+ end
107
+
108
+ it 'fails with an invalid interval_id 14-20' do
109
+ expect { subject.granularity_from_interval_id('14-20') }.to raise_error ArgumentError
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Models::Token do
4
+ subject { Ably::Models::Token }
5
+
6
+ it_behaves_like 'a model', with_simple_attributes: %w(id capability client_id nonce) do
7
+ let(:model_args) { [] }
8
+ end
9
+
10
+ context 'defaults' do
11
+ let(:one_hour) { 60 * 60 }
12
+ let(:all_capabilities) { { "*" => ["*"] } }
13
+
14
+ it 'should default TTL to 1 hour' do
15
+ expect(Ably::Models::Token::DEFAULTS[:ttl]).to eql(one_hour)
16
+ end
17
+
18
+ it 'should default capability to all' do
19
+ expect(Ably::Models::Token::DEFAULTS[:capability]).to eql(all_capabilities)
20
+ end
21
+
22
+ it 'should only have defaults for :ttl and :capability' do
23
+ expect(Ably::Models::Token::DEFAULTS.keys).to contain_exactly(:ttl, :capability)
24
+ end
25
+ end
26
+
27
+ context 'attributes' do
28
+ let(:unique_value) { 'unique_value' }
29
+
30
+ context '#key_id' do
31
+ subject { Ably::Models::Token.new({ key: unique_value }) }
32
+ it 'retrieves attribute :key' do
33
+ expect(subject.key_id).to eql(unique_value)
34
+ end
35
+ end
36
+
37
+ { :issued_at => :issued_at, :expires_at => :expires }.each do |method_name, attribute|
38
+ let(:time) { Time.now }
39
+ context "##{method_name}" do
40
+ subject { Ably::Models::Token.new({ attribute.to_sym => time.to_i }) }
41
+
42
+ it "retrieves attribute :#{attribute} as Time" do
43
+ expect(subject.public_send(method_name)).to be_a(Time)
44
+ expect(subject.public_send(method_name).to_i).to eql(time.to_i)
45
+ end
46
+ end
47
+ end
48
+
49
+ context '#expired?' do
50
+ let(:expire_time) { Time.now + Ably::Models::Token::TOKEN_EXPIRY_BUFFER }
51
+
52
+ context 'once grace period buffer has passed' do
53
+ subject { Ably::Models::Token.new(expires: expire_time - 1) }
54
+
55
+ it 'is true' do
56
+ expect(subject.expired?).to eql(true)
57
+ end
58
+ end
59
+
60
+ context 'within grace period buffer' do
61
+ subject { Ably::Models::Token.new(expires: expire_time + 1) }
62
+
63
+ it 'is false' do
64
+ expect(subject.expired?).to eql(false)
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ context '==' do
71
+ let(:token_attributes) { { id: 'unique' } }
72
+
73
+ it 'is true when attributes are the same' do
74
+ new_token = -> { Ably::Models::Token.new(token_attributes) }
75
+ expect(new_token[]).to eq(new_token[])
76
+ end
77
+
78
+ it 'is false when attributes are not the same' do
79
+ expect(Ably::Models::Token.new(id: 1)).to_not eq(Ably::Models::Token.new(id: 2))
80
+ end
81
+
82
+ it 'is false when class type differs' do
83
+ expect(Ably::Models::Token.new(id: 1)).to_not eq(nil)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Modules::AsyncWrapper, :api_private do
4
+ include RSpec::EventMachine
5
+
6
+ let(:class_with_module) do
7
+ Class.new do
8
+ include Ably::Modules::AsyncWrapper
9
+
10
+ def operation(&success_callback)
11
+ async_wrap success_callback, &@block
12
+ end
13
+
14
+ def block=(block)
15
+ @block = block
16
+ end
17
+ end
18
+ end
19
+ let(:subject) { class_with_module.new }
20
+ let(:result) { random_str }
21
+ let(:sleep_time) { 0.1 }
22
+
23
+ before do
24
+ subject.block = block
25
+ end
26
+
27
+ context '#async_wrap blocking block' do
28
+ context 'returns result' do
29
+ let(:block) do
30
+ proc do
31
+ sleep sleep_time
32
+ result
33
+ end
34
+ end
35
+
36
+ it 'calls the success_callback block with result when provided' do
37
+ run_reactor do
38
+ subject.operation do |result|
39
+ expect(result).to eql(result)
40
+ stop_reactor
41
+ end
42
+ end
43
+ end
44
+
45
+ it 'returns a deferrable that succeeds with result' do
46
+ run_reactor do
47
+ deferrable = subject.operation
48
+ expect(deferrable).to be_a(EventMachine::Deferrable)
49
+ deferrable.callback do |result|
50
+ expect(result).to eql(result)
51
+ stop_reactor
52
+ end
53
+ end
54
+ end
55
+
56
+ it 'does not call the errback' do
57
+ run_reactor do
58
+ deferrable = subject.operation
59
+ expect(deferrable).to be_a(EventMachine::Deferrable)
60
+ deferrable.callback do |result|
61
+ expect(result).to eql(result)
62
+ EventMachine.add_timer(sleep_time * 2) { stop_reactor }
63
+ end
64
+ deferrable.errback do |result|
65
+ raise 'Errback should not have been called'
66
+ end
67
+ end
68
+ end
69
+
70
+ it 'does not block EventMachine' do
71
+ run_reactor do
72
+ timers_called = 0
73
+ EventMachine.add_periodic_timer(sleep_time / 5) { timers_called += 1 }
74
+
75
+ subject.operation do |result|
76
+ expect(timers_called).to be >= 4
77
+ stop_reactor
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ context 'raises an Exception' do
84
+ let(:block) do
85
+ proc do
86
+ sleep sleep_time
87
+ raise RuntimeError, 'Intentional'
88
+ end
89
+ end
90
+
91
+ it 'calls the errback block of the deferrable' do
92
+ run_reactor do
93
+ deferrable = subject.operation
94
+ expect(deferrable).to be_a(EventMachine::Deferrable)
95
+ deferrable.errback do |error|
96
+ expect(error).to be_a(RuntimeError)
97
+ expect(error.message).to match(/Intentional/)
98
+ stop_reactor
99
+ end
100
+ end
101
+ end
102
+
103
+ it 'does not call the success_callback block' do
104
+ run_reactor do
105
+ subject.operation do |result|
106
+ raise 'Callback should not have been called'
107
+ end
108
+ EventMachine.add_timer(sleep_time * 2) { stop_reactor }
109
+ end
110
+ end
111
+
112
+ it 'does not call the callback block of the deferrable' do
113
+ run_reactor do
114
+ deferrable = subject.operation
115
+ expect(deferrable).to be_a(EventMachine::Deferrable)
116
+ deferrable.callback do |result|
117
+ raise 'Callback should not have been called'
118
+ end
119
+ EventMachine.add_timer(sleep_time * 2) { stop_reactor }
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Modules::Conversions, :api_private do
4
+ let(:class_with_module) { Class.new do; include Ably::Modules::Conversions; end }
5
+ let(:subject) { class_with_module.new }
6
+ before do
7
+ # make method being tested public
8
+ class_with_module.class_eval %{ public :#{method} }
9
+ end
10
+
11
+ context '#as_since_epoch' do
12
+ let(:method) { :as_since_epoch }
13
+
14
+ context 'with time' do
15
+ let(:time) { Time.new }
16
+
17
+ it 'converts to milliseconds by default' do
18
+ expect(subject.as_since_epoch(time)).to be_within(1).of(time.to_f * 1_000)
19
+ end
20
+
21
+ it 'converted to seconds' do
22
+ expect(subject.as_since_epoch(time, granularity: :s)).to eql(time.to_i)
23
+ end
24
+ end
25
+
26
+ context 'with numeric' do
27
+ it 'converts to integer' do
28
+ expect(subject.as_since_epoch(1.01)).to eql(1)
29
+ end
30
+
31
+ it 'accepts integers' do
32
+ expect(subject.as_since_epoch(1)).to eql(1)
33
+ end
34
+ end
35
+
36
+ context 'with any other object' do
37
+ it 'raises an exception' do
38
+ expect { subject.as_since_epoch(Object.new) }.to raise_error ArgumentError
39
+ end
40
+ end
41
+ end
42
+
43
+ context '#as_time_from_epoch' do
44
+ let(:method) { :as_time_from_epoch }
45
+ let(:time) { Time.new }
46
+
47
+ context 'with numeric' do
48
+ let(:millisecond) { Time.new.to_f * 1_000 }
49
+ let(:seconds) { Time.new.to_f }
50
+
51
+ it 'converts to Time from milliseconds by default' do
52
+ expect(subject.as_time_from_epoch(millisecond).to_f).to be_within(0.01).of(time.to_f)
53
+ end
54
+
55
+ it 'converts to Time from seconds' do
56
+ expect(subject.as_time_from_epoch(seconds, granularity: :s).to_i).to eql(time.to_i)
57
+ end
58
+ end
59
+
60
+ context 'with Time' do
61
+ it 'leaves intact' do
62
+ expect(subject.as_time_from_epoch(time)).to eql(time)
63
+ end
64
+ end
65
+
66
+ context 'with any other object' do
67
+ it 'raises an exception' do
68
+ expect { subject.as_time_from_epoch(Object.new) }.to raise_error ArgumentError
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,272 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ably::Modules::Enum, :api_private do
4
+ class ExampleClassWithEnum
5
+ extend Ably::Modules::Enum
6
+ ENUMEXAMPLE = ruby_enum('ENUMEXAMPLE', :value_zero, 'value_1', :value_snake_case_2, :SentenceCase)
7
+ end
8
+
9
+ let(:enum) { ExampleClassWithEnum::ENUMEXAMPLE }
10
+ let(:enum_name) { 'ENUMEXAMPLE' }
11
+
12
+ context 'convertor method added to class' do
13
+ subject { ExampleClassWithEnum }
14
+
15
+ it 'converts symbols' do
16
+ expect(subject.ENUMEXAMPLE(:value_zero)).to eql(enum.get(:value_zero))
17
+ end
18
+
19
+ it 'converts strings' do
20
+ expect(subject.ENUMEXAMPLE('ValueZero')).to eql(enum.get(:value_zero))
21
+ end
22
+
23
+ it 'converts integer index' do
24
+ expect(subject.ENUMEXAMPLE(0)).to eql(enum.get(:value_zero))
25
+ end
26
+ end
27
+
28
+ context 'convertor method added to instance' do
29
+ subject { ExampleClassWithEnum.new }
30
+
31
+ it 'converts symbols' do
32
+ expect(subject.ENUMEXAMPLE(:value_zero)).to eql(enum.get(:value_zero))
33
+ end
34
+
35
+ it 'converts strings' do
36
+ expect(subject.ENUMEXAMPLE('ValueZero')).to eql(enum.get(:value_zero))
37
+ end
38
+
39
+ it 'converts integer index' do
40
+ expect(subject.ENUMEXAMPLE(0)).to eql(enum.get(:value_zero))
41
+ end
42
+ end
43
+
44
+ context 'defined Enum from Array class' do
45
+ subject { enum }
46
+
47
+ it 'provides a MixedCase const for each provided value' do
48
+ expect(subject.ValueZero).to be_a(subject)
49
+ expect(subject.ValueSnakeCase2).to be_a(subject)
50
+ end
51
+
52
+ context '#get' do
53
+ context 'by integer index' do
54
+ let(:return_val) { subject.get(0) }
55
+ it 'returns an enum' do
56
+ expect(return_val).to be_a(subject)
57
+ expect(return_val.to_sym).to eql(:value_zero)
58
+ end
59
+ end
60
+
61
+ context 'by string value' do
62
+ let(:return_val) { subject.get('value_zero') }
63
+ it 'returns an enum' do
64
+ expect(return_val).to be_a(subject)
65
+ expect(return_val.to_sym).to eql(:value_zero)
66
+ end
67
+ end
68
+
69
+ context 'by symbol' do
70
+ let(:return_val) { subject.get(:sentence_case) }
71
+ it 'returns an enum' do
72
+ expect(return_val).to be_a(subject)
73
+ expect(return_val.to_sym).to eql(:sentence_case)
74
+ end
75
+ end
76
+
77
+ context 'by enum' do
78
+ let(:return_val) { subject.get(subject.get(:sentence_case)) }
79
+ it 'returns an enum' do
80
+ expect(return_val).to be_a(subject)
81
+ expect(return_val.to_sym).to eql(:sentence_case)
82
+ end
83
+ end
84
+
85
+ context 'by invalid type' do
86
+ let(:return_val) { subject.get(Array.new) }
87
+ it 'raises an error' do
88
+ expect { return_val }.to raise_error KeyError
89
+ end
90
+ end
91
+ end
92
+
93
+ context '#[]' do
94
+ let(:argument) { random_str }
95
+ before do
96
+ expect(subject).to receive(:get).with(argument).once.and_return(true)
97
+ end
98
+
99
+ it 'is an alias for get' do
100
+ subject[argument]
101
+ end
102
+ end
103
+
104
+ it 'returns the provided Enum name' do
105
+ expect(subject.name).to eql(enum_name)
106
+ end
107
+
108
+ specify '#to_s returns the Enum name' do
109
+ expect("#{subject}").to eql(enum_name)
110
+ end
111
+
112
+ context '#size' do
113
+ it 'returns the number of enum items' do
114
+ expect(subject.size).to eql(4)
115
+ end
116
+
117
+ it 'has alias #length' do
118
+ expect(subject.length).to eql(subject.size)
119
+ end
120
+ end
121
+
122
+ it 'freezes the Enum' do
123
+ expect(subject.send(:by_index)).to be_frozen
124
+ end
125
+
126
+ it 'prevents modification' do
127
+ expect { subject.send(:define_values, :enum_id) }.to raise_error RuntimeError, /cannot be modified/
128
+ end
129
+
130
+ it 'behaves like Enumerable' do
131
+ expect(subject.map(&:to_sym)).to eql([:value_zero, :value_1, :value_snake_case_2, :sentence_case])
132
+ end
133
+
134
+ context '#each' do
135
+ it 'returns an enumerator' do
136
+ expect(subject.each).to be_a(Enumerator)
137
+ end
138
+
139
+ it 'yields each channel' do
140
+ expect(subject.each.map(&:to_sym)).to eql([:value_zero, :value_1, :value_snake_case_2, :sentence_case])
141
+ end
142
+ end
143
+ end
144
+
145
+ context 'defined Enum from Hash class' do
146
+ class ExampleClassWithEnumFromHash
147
+ extend Ably::Modules::Enum
148
+ ENUMEXAMPLE = ruby_enum('ENUMEXAMPLE',
149
+ value_one: 1,
150
+ value_five: 5
151
+ )
152
+ end
153
+
154
+ subject { ExampleClassWithEnumFromHash::ENUMEXAMPLE }
155
+
156
+ it 'provides a MixedCase const for each provided value' do
157
+ expect(subject.ValueOne).to be_a(subject)
158
+ expect(subject.ValueFive).to be_a(subject)
159
+ end
160
+
161
+ context '#get' do
162
+ context 'by integer index for 1' do
163
+ let(:return_val) { subject.get(1) }
164
+ it 'returns an enum' do
165
+ expect(return_val).to be_a(subject)
166
+ expect(return_val.to_sym).to eql(:value_one)
167
+ end
168
+ end
169
+
170
+ context 'by integer index for 5' do
171
+ let(:return_val) { subject.get(5) }
172
+ it 'returns an enum' do
173
+ expect(return_val).to be_a(subject)
174
+ expect(return_val.to_sym).to eql(:value_five)
175
+ end
176
+ end
177
+
178
+ context 'by invalid integer index' do
179
+ let(:return_val) { subject.get(0) }
180
+ it 'raises an exception' do
181
+ expect { return_val }.to raise_error KeyError
182
+ end
183
+ end
184
+
185
+ context 'by string value' do
186
+ let(:return_val) { subject.get('value_five') }
187
+ it 'returns an enum' do
188
+ expect(return_val).to be_a(subject)
189
+ expect(return_val.to_sym).to eql(:value_five)
190
+ expect(return_val.to_i).to eql(5)
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ context 'defined Enum from another Enum' do
197
+ class ExampleBaseEnum
198
+ extend Ably::Modules::Enum
199
+ ENUMEXAMPLE = ruby_enum('ENUMEXAMPLE', :one, :second_enum)
200
+ end
201
+
202
+ class ExampleOtherEnum
203
+ extend Ably::Modules::Enum
204
+ ENUMEXAMPLE = ruby_enum('ENUMEXAMPLE', ExampleBaseEnum::ENUMEXAMPLE)
205
+ end
206
+
207
+ subject { ExampleOtherEnum::ENUMEXAMPLE }
208
+
209
+ it 'provides a MixedCase const for each provided value' do
210
+ expect(subject.One).to be_a(subject)
211
+ expect(subject.SecondEnum).to be_a(subject)
212
+ end
213
+ end
214
+
215
+ context 'Enum instance' do
216
+ context '#==' do
217
+ subject { enum.get(:value_snake_case_2) }
218
+
219
+ it 'compares with a symbol' do
220
+ expect(subject).to eq(:value_Snake_Case_2)
221
+ end
222
+
223
+ it 'compares with a string' do
224
+ expect(subject).to eq('ValueSnakeCase2')
225
+ end
226
+
227
+ it 'compares with a integer index' do
228
+ expect(subject).to eq(subject.to_i)
229
+ end
230
+
231
+ it 'compares with itself' do
232
+ expect(subject).to eq(subject)
233
+ end
234
+
235
+ it 'compares with other Objects' do
236
+ expect(subject).to_not eq(Object.new)
237
+ end
238
+ end
239
+
240
+ context '#to_s' do
241
+ subject { enum.get(:value_zero) }
242
+
243
+ it 'returns ENUMNAME.CamelCase name' do
244
+ expect(subject.to_s).to eql("#{enum_name}.ValueZero")
245
+ end
246
+ end
247
+
248
+ context '#to_sym' do
249
+ subject { enum.get(:value_zero) }
250
+
251
+ it 'returns a snake_case symbol' do
252
+ expect(subject.to_sym).to eql(:value_zero)
253
+ end
254
+ end
255
+
256
+ context '#to_i' do
257
+ subject { enum.get(:value_1) }
258
+
259
+ it 'returns the Enum index' do
260
+ expect(subject.to_i).to eql(1)
261
+ end
262
+ end
263
+
264
+ context '#to_json' do
265
+ subject { enum.get(:value_1) }
266
+
267
+ it 'returns a symbol string key value' do
268
+ expect(subject.to_json).to eql('"value_1"')
269
+ end
270
+ end
271
+ end
272
+ end