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.
- checksums.yaml +13 -5
- data/.gitmodules +1 -1
- data/.rspec +1 -0
- data/.travis.yml +7 -3
- data/SPEC.md +495 -419
- data/ably-rest.gemspec +19 -5
- data/lib/ably-rest.rb +9 -1
- data/lib/submodules/ably-ruby/.gitignore +6 -0
- data/lib/submodules/ably-ruby/.rspec +1 -0
- data/lib/submodules/ably-ruby/.ruby-version.old +1 -0
- data/lib/submodules/ably-ruby/.travis.yml +10 -0
- data/lib/submodules/ably-ruby/Gemfile +4 -0
- data/lib/submodules/ably-ruby/LICENSE.txt +22 -0
- data/lib/submodules/ably-ruby/README.md +122 -0
- data/lib/submodules/ably-ruby/Rakefile +34 -0
- data/lib/submodules/ably-ruby/SPEC.md +1794 -0
- data/lib/submodules/ably-ruby/ably.gemspec +36 -0
- data/lib/submodules/ably-ruby/lib/ably.rb +12 -0
- data/lib/submodules/ably-ruby/lib/ably/auth.rb +438 -0
- data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/logger.rb +102 -0
- data/lib/submodules/ably-ruby/lib/ably/models/error_info.rb +37 -0
- data/lib/submodules/ably-ruby/lib/ably/models/idiomatic_ruby_wrapper.rb +223 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message.rb +132 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base.rb +108 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/base64.rb +40 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/cipher.rb +83 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/json.rb +34 -0
- data/lib/submodules/ably-ruby/lib/ably/models/message_encoders/utf8.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/models/nil_logger.rb +20 -0
- data/lib/submodules/ably-ruby/lib/ably/models/paginated_resource.rb +173 -0
- data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +147 -0
- data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +210 -0
- data/lib/submodules/ably-ruby/lib/ably/models/stat.rb +161 -0
- data/lib/submodules/ably-ruby/lib/ably/models/token.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/ably.rb +15 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/async_wrapper.rb +62 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/channels_collection.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +100 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/encodeable.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/enum.rb +202 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_emitter.rb +128 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/event_machine_helpers.rb +26 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/http_helpers.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/message_pack.rb +14 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/model_common.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +153 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/state_machine.rb +57 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime.rb +64 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +298 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +69 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/channels.rb +50 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +184 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +70 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +445 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +368 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +91 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/connection/websocket_transport.rb +188 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/models/nil_channel.rb +30 -0
- data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +564 -0
- data/lib/submodules/ably-ruby/lib/ably/rest.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +104 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/channels.rb +44 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +396 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/encoder.rb +49 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/exceptions.rb +41 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/external_exceptions.rb +24 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/fail_if_unsupported_mime_type.rb +17 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/logger.rb +58 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_json.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/middleware/parse_message_pack.rb +27 -0
- data/lib/submodules/ably-ruby/lib/ably/rest/presence.rb +92 -0
- data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +105 -0
- data/lib/submodules/ably-ruby/lib/ably/util/pub_sub.rb +43 -0
- data/lib/submodules/ably-ruby/lib/ably/version.rb +3 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +154 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +558 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +119 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +575 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +785 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +457 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +55 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +1001 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +23 -0
- data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +27 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +564 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/base_spec.rb +165 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +134 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/channels_spec.rb +41 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +273 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/message_spec.rb +247 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +292 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/stats_spec.rb +172 -0
- data/lib/submodules/ably-ruby/spec/acceptance/rest/time_spec.rb +15 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-128.json +56 -0
- data/lib/submodules/ably-ruby/spec/resources/crypto-data-256.json +56 -0
- data/lib/submodules/ably-ruby/spec/rspec_config.rb +57 -0
- data/lib/submodules/ably-ruby/spec/shared/client_initializer_behaviour.rb +212 -0
- data/lib/submodules/ably-ruby/spec/shared/model_behaviour.rb +86 -0
- data/lib/submodules/ably-ruby/spec/shared/protocol_msgbus_behaviour.rb +36 -0
- data/lib/submodules/ably-ruby/spec/spec_helper.rb +20 -0
- data/lib/submodules/ably-ruby/spec/support/api_helper.rb +60 -0
- data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +104 -0
- data/lib/submodules/ably-ruby/spec/support/markdown_spec_formatter.rb +118 -0
- data/lib/submodules/ably-ruby/spec/support/private_api_formatter.rb +36 -0
- data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +32 -0
- data/lib/submodules/ably-ruby/spec/support/random_helper.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/rest_testapp_before_retry.rb +15 -0
- data/lib/submodules/ably-ruby/spec/support/test_app.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +68 -0
- data/lib/submodules/ably-ruby/spec/unit/logger_spec.rb +146 -0
- data/lib/submodules/ably-ruby/spec/unit/models/error_info_spec.rb +18 -0
- data/lib/submodules/ably-ruby/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +349 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/base64_spec.rb +181 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/cipher_spec.rb +260 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/json_spec.rb +135 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_encoders/utf8_spec.rb +56 -0
- data/lib/submodules/ably-ruby/spec/unit/models/message_spec.rb +389 -0
- data/lib/submodules/ably-ruby/spec/unit/models/paginated_resource_spec.rb +288 -0
- data/lib/submodules/ably-ruby/spec/unit/models/presence_message_spec.rb +386 -0
- data/lib/submodules/ably-ruby/spec/unit/models/protocol_message_spec.rb +315 -0
- data/lib/submodules/ably-ruby/spec/unit/models/stat_spec.rb +113 -0
- data/lib/submodules/ably-ruby/spec/unit/models/token_spec.rb +86 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +124 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/conversions_spec.rb +72 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/enum_spec.rb +272 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/event_emitter_spec.rb +184 -0
- data/lib/submodules/ably-ruby/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channel_spec.rb +206 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/channels_spec.rb +81 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/client_spec.rb +30 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/connection_spec.rb +33 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/presence_spec.rb +111 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/realtime_spec.rb +9 -0
- data/lib/submodules/ably-ruby/spec/unit/realtime/websocket_transport_spec.rb +25 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channel_spec.rb +109 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/channels_spec.rb +79 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/client_spec.rb +53 -0
- data/lib/submodules/ably-ruby/spec/unit/rest/rest_spec.rb +10 -0
- data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +87 -0
- data/lib/submodules/ably-ruby/spec/unit/util/pub_sub_spec.rb +86 -0
- metadata +182 -27
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
shared_examples 'a model' do |shared_options = {}|
|
|
4
|
+
let(:base_model_options) { shared_options.fetch(:base_model_options, {}) }
|
|
5
|
+
let(:args) { ([base_model_options.merge(model_options)] + model_args) }
|
|
6
|
+
let(:model) { subject.new(*args) }
|
|
7
|
+
|
|
8
|
+
context 'attributes' do
|
|
9
|
+
let(:unique_value) { random_str }
|
|
10
|
+
|
|
11
|
+
Array(shared_options[:with_simple_attributes]).each do |attribute|
|
|
12
|
+
context "##{attribute}" do
|
|
13
|
+
let(:model_options) { { attribute.to_sym => unique_value } }
|
|
14
|
+
|
|
15
|
+
it "retrieves attribute :#{attribute}" do
|
|
16
|
+
expect(model.public_send(attribute)).to eql(unique_value)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context '#hash', :api_private do
|
|
22
|
+
let(:model_options) { { action: 5 } }
|
|
23
|
+
|
|
24
|
+
it 'provides access to #hash' do
|
|
25
|
+
expect(model.hash).to eq(model_options)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context '#[]', :api_private do
|
|
30
|
+
let(:model_options) { { unusual: 'attribute' } }
|
|
31
|
+
|
|
32
|
+
it 'provides accessor method to #hash' do
|
|
33
|
+
expect(model[:unusual]).to eql('attribute')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context '#==' do
|
|
39
|
+
let(:model_options) { { channel: 'unique' } }
|
|
40
|
+
|
|
41
|
+
it 'is true when attributes are the same' do
|
|
42
|
+
new_message = -> { subject.new(*args) }
|
|
43
|
+
expect(new_message[]).to eq(new_message[])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'is false when attributes are not the same' do
|
|
47
|
+
expect(subject.new(*[action: 1] + model_args)).to_not eq(subject.new(*[action: 2] + model_args))
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'is false when class type differs' do
|
|
51
|
+
expect(subject.new(*[action: 1] + model_args)).to_not eq(nil)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context '#to_msgpack', :api_private do
|
|
56
|
+
let(:model_options) { { name: 'test', action: 0, channel_snake_case: 'unique' } }
|
|
57
|
+
let(:serialized) { model.to_msgpack }
|
|
58
|
+
|
|
59
|
+
it 'returns a msgpack object with Ably payload naming' do
|
|
60
|
+
expect(MessagePack.unpack(serialized)).to include('channelSnakeCase' => 'unique')
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context '#to_json', :api_private do
|
|
65
|
+
let(:model_options) { { name: 'test', action: 0, channel_snake_case: 'unique' } }
|
|
66
|
+
let(:serialized) { model.to_json }
|
|
67
|
+
|
|
68
|
+
it 'returns a JSON string with Ably payload naming' do
|
|
69
|
+
expect(JSON.parse(serialized)).to include('channelSnakeCase' => 'unique')
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'is immutable' do
|
|
74
|
+
let(:model_options) { { channel: 'name' } }
|
|
75
|
+
|
|
76
|
+
it 'prevents changes' do
|
|
77
|
+
expect { model.hash[:channel] = 'new' }.to raise_error RuntimeError, /can't modify frozen.*Hash/
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'dups options' do
|
|
81
|
+
expect(model.hash[:channel]).to eql('name')
|
|
82
|
+
model_options[:channel] = 'new'
|
|
83
|
+
expect(model.hash[:channel]).to eql('name')
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
shared_examples 'a protocol message bus' do
|
|
2
|
+
describe '__protocol_msgbus__ PubSub', :api_private do
|
|
3
|
+
let(:protocol_message) do
|
|
4
|
+
Ably::Models::ProtocolMessage.new(
|
|
5
|
+
action: 15,
|
|
6
|
+
channel: 'channel',
|
|
7
|
+
msg_serial: 0,
|
|
8
|
+
messages: []
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
specify 'supports valid ProtocolMessage messages' do
|
|
13
|
+
received = 0
|
|
14
|
+
msgbus.subscribe(:protocol_message) { received += 1 }
|
|
15
|
+
expect { msgbus.publish(:protocol_message, protocol_message) }.to change { received }.to(1)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
specify 'fail with unacceptable STATE event names' do
|
|
19
|
+
expect { msgbus.subscribe(:invalid) }.to raise_error KeyError
|
|
20
|
+
expect { msgbus.publish(:invalid) }.to raise_error KeyError
|
|
21
|
+
expect { msgbus.unsubscribe(:invalid) }.to raise_error KeyError
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
shared_examples 'an incoming protocol message bus' do
|
|
27
|
+
it_behaves_like 'a protocol message bus' do
|
|
28
|
+
let(:msgbus) { subject.__incoming_protocol_msgbus__ }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
shared_examples 'an outgoing protocol message bus' do
|
|
33
|
+
it_behaves_like 'a protocol message bus' do
|
|
34
|
+
let(:msgbus) { subject.__outgoing_protocol_msgbus__ }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Output the message to the console
|
|
2
|
+
# Useful for debugging as clearly visible, and name is not used anywhere else in library as opposed to debug or puts
|
|
3
|
+
def console(message)
|
|
4
|
+
puts "\033[31m[#{Time.now.strftime('%H:%M:%S.%L')}]\033[0m \033[33m#{message}\033[0m"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'webmock/rspec'
|
|
8
|
+
|
|
9
|
+
require 'ably'
|
|
10
|
+
|
|
11
|
+
require 'support/api_helper'
|
|
12
|
+
require 'support/private_api_formatter'
|
|
13
|
+
require 'support/protocol_helper'
|
|
14
|
+
require 'support/random_helper'
|
|
15
|
+
|
|
16
|
+
require 'rspec_config'
|
|
17
|
+
|
|
18
|
+
# EM Helper must be loaded after rspec_config to ensure around block occurs before RSpec retry
|
|
19
|
+
require 'support/event_machine_helper'
|
|
20
|
+
require 'support/rest_testapp_before_retry'
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'support/test_app'
|
|
2
|
+
|
|
3
|
+
module ApiHelper
|
|
4
|
+
def app_id
|
|
5
|
+
TestApp.instance.app_id
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def key_id
|
|
9
|
+
TestApp.instance.key_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def key_secret
|
|
13
|
+
api_key.split(':')[1]
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def api_key
|
|
17
|
+
TestApp.instance.api_key
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def restricted_api_key
|
|
21
|
+
TestApp.instance.restricted_api_key
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def environment
|
|
25
|
+
TestApp.instance.environment
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def reload_test_app
|
|
29
|
+
WebMock.disable!
|
|
30
|
+
TestApp.reload
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def encode64(text)
|
|
34
|
+
Base64.encode64(text).gsub("\n", '')
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
RSpec.configure do |config|
|
|
39
|
+
config.include ApiHelper
|
|
40
|
+
|
|
41
|
+
config.before(:suite) do
|
|
42
|
+
WebMock.disable!
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
config.after(:suite) do
|
|
46
|
+
WebMock.disable!
|
|
47
|
+
TestApp.instance.delete
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module ApiPreloader
|
|
52
|
+
def self.included(mod)
|
|
53
|
+
WebMock.disable!
|
|
54
|
+
TestApp.instance.api_key
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
RSpec.configure do |config|
|
|
58
|
+
config.include self, :file_path => %r(spec/acceptance)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'eventmachine'
|
|
2
|
+
require 'rspec'
|
|
3
|
+
require 'timeout'
|
|
4
|
+
|
|
5
|
+
module RSpec
|
|
6
|
+
module EventMachine
|
|
7
|
+
extend self
|
|
8
|
+
|
|
9
|
+
DEFAULT_TIMEOUT = 10
|
|
10
|
+
|
|
11
|
+
def run_reactor(timeout = DEFAULT_TIMEOUT)
|
|
12
|
+
Timeout::timeout(timeout + 0.5) do
|
|
13
|
+
::EventMachine.run do
|
|
14
|
+
yield
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def stop_reactor
|
|
20
|
+
::EventMachine.next_tick do
|
|
21
|
+
::EventMachine.stop
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Allows multiple Deferrables to be passed in and calls the provided block when
|
|
26
|
+
# all success callbacks have completed
|
|
27
|
+
def when_all(*deferrables)
|
|
28
|
+
raise ArgumentError, 'Block required' unless block_given?
|
|
29
|
+
|
|
30
|
+
options = if deferrables.last.kind_of?(Hash)
|
|
31
|
+
deferrables.pop
|
|
32
|
+
else
|
|
33
|
+
{}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
successful_deferrables = {}
|
|
37
|
+
|
|
38
|
+
deferrables.each do |deferrable|
|
|
39
|
+
deferrable.callback do
|
|
40
|
+
successful_deferrables[deferrable.object_id] = true
|
|
41
|
+
if successful_deferrables.keys.sort == deferrables.map(&:object_id).sort
|
|
42
|
+
if options[:and_wait]
|
|
43
|
+
::EventMachine.add_timer(options[:and_wait]) { yield }
|
|
44
|
+
else
|
|
45
|
+
yield
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
deferrable.errback do |error|
|
|
51
|
+
raise RuntimeError, "Deferrable failed: #{error.message}"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def wait_until(condition_block, &block)
|
|
57
|
+
raise ArgumentError, 'Block required' unless block_given?
|
|
58
|
+
|
|
59
|
+
yield if condition_block.call
|
|
60
|
+
::EventMachine.add_timer(0.1) do
|
|
61
|
+
wait_until condition_block, &block
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
RSpec.configure do |config|
|
|
68
|
+
config.before(:context, :event_machine) do |context|
|
|
69
|
+
context.class.class_eval do
|
|
70
|
+
include RSpec::EventMachine
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Run the test block wrapped in an EventMachine reactor that has a configured timeout.
|
|
75
|
+
# As RSpec does not provide an API to wrap blocks, accessing the instance variables is required.
|
|
76
|
+
# Note, if you start a reactor and simply run the example with example#run then the example
|
|
77
|
+
# will run and not wait for the reactor to stop thus triggering after callbacks prematurely.
|
|
78
|
+
#
|
|
79
|
+
config.around(:example, :event_machine) do |example|
|
|
80
|
+
timeout = if example.metadata[:em_timeout].is_a?(Numeric)
|
|
81
|
+
example.metadata[:em_timeout]
|
|
82
|
+
else
|
|
83
|
+
RSpec::EventMachine::DEFAULT_TIMEOUT
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
example_block = example.example.instance_variable_get('@example_block')
|
|
87
|
+
example_group_instance = example.example.instance_variable_get('@example_group_instance')
|
|
88
|
+
|
|
89
|
+
event_machine_block = Proc.new do
|
|
90
|
+
RSpec::EventMachine.run_reactor(timeout) do
|
|
91
|
+
example_group_instance.instance_exec(example, &example_block)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
example.example.instance_variable_set('@example_block', event_machine_block)
|
|
96
|
+
|
|
97
|
+
example.run
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
config.before(:example) do
|
|
101
|
+
# Ensure EventMachine shutdown hooks are deregistered for every test
|
|
102
|
+
EventMachine.instance_variable_set '@tails', []
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Ably
|
|
2
|
+
module RSpec
|
|
3
|
+
# Generate Markdown Specification from the RSpec public API tests
|
|
4
|
+
#
|
|
5
|
+
class MarkdownSpecFormatter
|
|
6
|
+
::RSpec::Core::Formatters.register self, :start, :close,
|
|
7
|
+
:example_group_started, :example_group_finished,
|
|
8
|
+
:example_passed, :example_failed, :example_pending,
|
|
9
|
+
:dump_summary
|
|
10
|
+
|
|
11
|
+
def initialize(output)
|
|
12
|
+
@output = if documenting_rest_only?
|
|
13
|
+
File.open(File.expand_path('../../../../../../SPEC.md', __FILE__), 'w')
|
|
14
|
+
else
|
|
15
|
+
File.open(File.expand_path('../../../SPEC.md', __FILE__), 'w')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
@indent = 0
|
|
19
|
+
@passed = 0
|
|
20
|
+
@pending = 0
|
|
21
|
+
@failed = 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def start(notification)
|
|
25
|
+
puts "\n\e[33m --> Creating SPEC.md <--\e[0m\n"
|
|
26
|
+
scope = if defined?(Ably::Realtime)
|
|
27
|
+
'Real-time & REST'
|
|
28
|
+
else
|
|
29
|
+
'REST'
|
|
30
|
+
end
|
|
31
|
+
output.write "# Ably #{scope} Client Library #{Ably::VERSION} Specification\n"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def close(notification)
|
|
35
|
+
output.close
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def example_group_started(notification)
|
|
39
|
+
output.write "#{indent_prefix}#{notification.group.description}\n"
|
|
40
|
+
output.write "_(see #{heading_location_path(notification)})_\n" if indent == 0
|
|
41
|
+
@indent += 1
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def example_group_finished(notification)
|
|
45
|
+
@indent -= 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def example_passed(notification)
|
|
49
|
+
unless notification.example.metadata[:api_private]
|
|
50
|
+
output.write "#{indent_prefix}#{example_name_and_link(notification)}\n"
|
|
51
|
+
@passed += 1
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def example_failed(notification)
|
|
56
|
+
unless notification.example.metadata[:api_private]
|
|
57
|
+
output.write "#{indent_prefix}FAILED: ~~#{example_name_and_link(notification)}~~\n"
|
|
58
|
+
@failed += 1
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def example_pending(notification)
|
|
63
|
+
unless notification.example.metadata[:api_private]
|
|
64
|
+
output.write "#{indent_prefix}PENDING: *#{example_name_and_link(notification)}*\n"
|
|
65
|
+
@pending += 1
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def dump_summary(notification)
|
|
70
|
+
output.write <<-EOF.gsub(' ', '')
|
|
71
|
+
|
|
72
|
+
-------
|
|
73
|
+
|
|
74
|
+
## Test summary
|
|
75
|
+
|
|
76
|
+
* Passing tests: #{@passed}
|
|
77
|
+
* Pending tests: #{@pending}
|
|
78
|
+
* Failing tests: #{@failed}
|
|
79
|
+
EOF
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
attr_reader :output, :indent
|
|
84
|
+
|
|
85
|
+
def documenting_rest_only?
|
|
86
|
+
File.exists?(File.expand_path('../../../../../../ably-rest.gemspec', __FILE__))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def example_name_and_link(notification)
|
|
90
|
+
"[#{notification.example.metadata[:description]}](#{path_for(notification.example.location).gsub(/\:(\d+)/, '#L\1')})"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def heading_location_path(notification)
|
|
94
|
+
"[#{notification.group.location.gsub(/\:(\d+)/, '').gsub(%r{^\.\/}, '')}](#{path_for(notification.group.location).gsub(/\:(\d+)/, '')})"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def path_for(location)
|
|
98
|
+
if documenting_rest_only?
|
|
99
|
+
"https://github.com/ably/ably-ruby/tree/#{submodule_sha}#{location.gsub(%r{^\./lib/submodules/ably-ruby}, '')}"
|
|
100
|
+
else
|
|
101
|
+
location
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def submodule_sha
|
|
106
|
+
@sha ||= `git ls-tree HEAD:lib/submodules grep ably-ruby`[/^\w+\s+\w+\s+(\w+)/, 1]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def indent_prefix
|
|
110
|
+
if indent > 0
|
|
111
|
+
"#{' ' * indent}* "
|
|
112
|
+
else
|
|
113
|
+
"\n### "
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Ably::RSpec
|
|
2
|
+
# PrivateApiFormatter is an RSpec Formatter that prefixes all tests that are part of a Private API with '(private)'
|
|
3
|
+
#
|
|
4
|
+
# Private API methods are tested for this library, but every implementation of the Ably client library
|
|
5
|
+
# will likely be different and thus the private API method tests are not shared.
|
|
6
|
+
#
|
|
7
|
+
# Filter private API tests with `rspec --tag ~api_private`
|
|
8
|
+
#
|
|
9
|
+
class PrivateApiFormatter
|
|
10
|
+
::RSpec::Core::Formatters.register self, :example_started
|
|
11
|
+
|
|
12
|
+
def initialize(output)
|
|
13
|
+
@output = output
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def example_started(notification)
|
|
17
|
+
if notification.example.metadata[:api_private]
|
|
18
|
+
notification.example.metadata[:description] = "#{yellow('(private)')} #{green(notification.example.metadata[:description])}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
def colorize(color_code, string)
|
|
24
|
+
"\e[#{color_code}m#{string}\e[0m"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def yellow(string)
|
|
28
|
+
colorize(33, string)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def green(string)
|
|
33
|
+
colorize(32, string)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|