ably 0.6.2 → 0.7.0
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 +4 -4
- data/.rspec +1 -0
- data/.ruby-version.old +1 -0
- data/.travis.yml +0 -2
- data/Rakefile +22 -4
- data/SPEC.md +1676 -0
- data/ably.gemspec +1 -1
- data/lib/ably.rb +0 -8
- data/lib/ably/auth.rb +54 -46
- data/lib/ably/exceptions.rb +19 -5
- data/lib/ably/logger.rb +1 -1
- data/lib/ably/models/error_info.rb +1 -1
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
- data/lib/ably/models/message.rb +15 -12
- data/lib/ably/models/message_encoders/base.rb +6 -5
- data/lib/ably/models/message_encoders/base64.rb +1 -0
- data/lib/ably/models/message_encoders/cipher.rb +6 -3
- data/lib/ably/models/message_encoders/json.rb +1 -0
- data/lib/ably/models/message_encoders/utf8.rb +2 -9
- data/lib/ably/models/nil_logger.rb +20 -0
- data/lib/ably/models/paginated_resource.rb +5 -2
- data/lib/ably/models/presence_message.rb +21 -12
- data/lib/ably/models/protocol_message.rb +22 -6
- data/lib/ably/modules/ably.rb +11 -0
- data/lib/ably/modules/async_wrapper.rb +2 -0
- data/lib/ably/modules/conversions.rb +23 -3
- data/lib/ably/modules/encodeable.rb +2 -1
- data/lib/ably/modules/enum.rb +2 -0
- data/lib/ably/modules/event_emitter.rb +7 -1
- data/lib/ably/modules/event_machine_helpers.rb +2 -0
- data/lib/ably/modules/http_helpers.rb +2 -0
- data/lib/ably/modules/model_common.rb +12 -2
- data/lib/ably/modules/state_emitter.rb +76 -0
- data/lib/ably/modules/state_machine.rb +53 -0
- data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
- data/lib/ably/modules/uses_state_machine.rb +74 -0
- data/lib/ably/realtime.rb +4 -2
- data/lib/ably/realtime/channel.rb +51 -58
- data/lib/ably/realtime/channel/channel_manager.rb +91 -0
- data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
- data/lib/ably/realtime/client.rb +70 -26
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
- data/lib/ably/realtime/connection.rb +135 -92
- data/lib/ably/realtime/connection/connection_manager.rb +216 -33
- data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
- data/lib/ably/realtime/models/nil_channel.rb +10 -1
- data/lib/ably/realtime/presence.rb +336 -92
- data/lib/ably/rest.rb +2 -2
- data/lib/ably/rest/channel.rb +13 -4
- data/lib/ably/rest/client.rb +138 -38
- data/lib/ably/rest/middleware/logger.rb +24 -3
- data/lib/ably/rest/presence.rb +12 -7
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
- data/spec/acceptance/realtime/channel_spec.rb +461 -120
- data/spec/acceptance/realtime/client_spec.rb +119 -0
- data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
- data/spec/acceptance/realtime/connection_spec.rb +571 -97
- data/spec/acceptance/realtime/message_spec.rb +347 -333
- data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
- data/spec/acceptance/realtime/presence_spec.rb +769 -239
- data/spec/acceptance/realtime/stats_spec.rb +14 -22
- data/spec/acceptance/realtime/time_spec.rb +16 -20
- data/spec/acceptance/rest/auth_spec.rb +425 -364
- data/spec/acceptance/rest/base_spec.rb +108 -176
- data/spec/acceptance/rest/channel_spec.rb +89 -89
- data/spec/acceptance/rest/channels_spec.rb +30 -32
- data/spec/acceptance/rest/client_spec.rb +273 -0
- data/spec/acceptance/rest/encoders_spec.rb +185 -0
- data/spec/acceptance/rest/message_spec.rb +186 -163
- data/spec/acceptance/rest/presence_spec.rb +150 -111
- data/spec/acceptance/rest/stats_spec.rb +45 -40
- data/spec/acceptance/rest/time_spec.rb +8 -10
- data/spec/rspec_config.rb +10 -1
- data/spec/shared/client_initializer_behaviour.rb +212 -0
- data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
- data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
- data/spec/spec_helper.rb +9 -0
- data/spec/support/api_helper.rb +11 -0
- data/spec/support/event_machine_helper.rb +101 -3
- data/spec/support/markdown_spec_formatter.rb +90 -0
- data/spec/support/private_api_formatter.rb +36 -0
- data/spec/support/protocol_helper.rb +32 -0
- data/spec/support/random_helper.rb +15 -0
- data/spec/support/test_app.rb +4 -0
- data/spec/unit/auth_spec.rb +68 -0
- data/spec/unit/logger_spec.rb +77 -66
- data/spec/unit/models/error_info_spec.rb +1 -1
- data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
- data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
- data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
- data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
- data/spec/unit/models/message_spec.rb +160 -15
- data/spec/unit/models/paginated_resource_spec.rb +29 -27
- data/spec/unit/models/presence_message_spec.rb +163 -20
- data/spec/unit/models/protocol_message_spec.rb +43 -8
- data/spec/unit/modules/async_wrapper_spec.rb +2 -3
- data/spec/unit/modules/conversions_spec.rb +1 -1
- data/spec/unit/modules/enum_spec.rb +2 -3
- data/spec/unit/modules/event_emitter_spec.rb +62 -5
- data/spec/unit/modules/state_emitter_spec.rb +283 -0
- data/spec/unit/realtime/channel_spec.rb +107 -2
- data/spec/unit/realtime/channels_spec.rb +1 -0
- data/spec/unit/realtime/client_spec.rb +8 -48
- data/spec/unit/realtime/connection_spec.rb +3 -3
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
- data/spec/unit/realtime/presence_spec.rb +13 -4
- data/spec/unit/realtime/realtime_spec.rb +0 -11
- data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
- data/spec/unit/rest/channel_spec.rb +109 -0
- data/spec/unit/rest/channels_spec.rb +4 -3
- data/spec/unit/rest/client_spec.rb +30 -125
- data/spec/unit/rest/rest_spec.rb +10 -0
- data/spec/unit/util/crypto_spec.rb +10 -5
- data/spec/unit/util/pub_sub_spec.rb +5 -5
- metadata +44 -12
- data/spec/integration/modules/state_emitter_spec.rb +0 -80
- data/spec/integration/rest/auth.rb +0 -9
@@ -1,17 +1,115 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'rspec'
|
1
3
|
require 'timeout'
|
2
4
|
|
3
5
|
module RSpec
|
4
6
|
module EventMachine
|
5
|
-
|
7
|
+
extend self
|
8
|
+
|
9
|
+
DEFAULT_TIMEOUT = 5
|
10
|
+
|
11
|
+
def run_reactor(timeout = DEFAULT_TIMEOUT)
|
6
12
|
Timeout::timeout(timeout + 0.5) do
|
7
|
-
|
13
|
+
::EventMachine.run do
|
8
14
|
yield
|
9
15
|
end
|
10
16
|
end
|
11
17
|
end
|
12
18
|
|
13
19
|
def stop_reactor
|
14
|
-
|
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, &block)
|
28
|
+
raise "Block expected" 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]) { block.call }
|
44
|
+
else
|
45
|
+
block.call
|
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
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
RSpec.configure do |config|
|
59
|
+
config.before(:context, :event_machine) do |context|
|
60
|
+
context.class.class_eval do
|
61
|
+
include RSpec::EventMachine
|
15
62
|
end
|
16
63
|
end
|
64
|
+
|
65
|
+
# Running a reactor block and then calling the example block with #call
|
66
|
+
# does not work as expected as the example completes immediately and the block
|
67
|
+
# calls after hooks before it returns the EventMachine loop.
|
68
|
+
#
|
69
|
+
# As there is no public API to inject around blocks correctly without calling the after blocks,
|
70
|
+
# we have to monkey patch the run_after_example method at https://github.com/rspec/rspec-core/blob/master/lib/rspec/core/example.rb#L376
|
71
|
+
# so that it does not run until we explicitly call it once the EventMachine reactor loop is finished.
|
72
|
+
#
|
73
|
+
def patch_example_block_with_surrounding_eventmachine_reactor(example)
|
74
|
+
example.example.class.class_eval do
|
75
|
+
alias_method :run_after_example_original, :run_after_example
|
76
|
+
public :run_after_example_original
|
77
|
+
|
78
|
+
# prevent after hooks being run for example until EventMachine reactor has finished
|
79
|
+
def run_after_example; end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def remove_patch_example_block(example)
|
84
|
+
example.example.class.class_eval do
|
85
|
+
remove_method :run_after_example
|
86
|
+
alias_method :run_after_example, :run_after_example_original
|
87
|
+
remove_method :run_after_example_original
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
config.around(:example, :event_machine) do |example|
|
92
|
+
timeout = if example.metadata[:em_timeout].is_a?(Numeric)
|
93
|
+
example.metadata[:em_timeout]
|
94
|
+
else
|
95
|
+
RSpec::EventMachine::DEFAULT_TIMEOUT
|
96
|
+
end
|
97
|
+
|
98
|
+
patch_example_block_with_surrounding_eventmachine_reactor example
|
99
|
+
|
100
|
+
begin
|
101
|
+
RSpec::EventMachine.run_reactor(timeout) do
|
102
|
+
example.call
|
103
|
+
raise example.exception if example.exception
|
104
|
+
end
|
105
|
+
ensure
|
106
|
+
example.example.run_after_example_original
|
107
|
+
remove_patch_example_block example
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
config.before(:example) do
|
112
|
+
# Ensure EventMachine shutdown hooks are deregistered for every test
|
113
|
+
EventMachine.instance_variable_set '@tails', []
|
114
|
+
end
|
17
115
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Ably::RSpec
|
2
|
+
# Generate Markdown Specification from the RSpec public API tests
|
3
|
+
#
|
4
|
+
class MarkdownSpecFormatter
|
5
|
+
::RSpec::Core::Formatters.register self, :start, :close,
|
6
|
+
:example_group_started, :example_group_finished,
|
7
|
+
:example_passed, :example_failed, :example_pending,
|
8
|
+
:dump_summary
|
9
|
+
|
10
|
+
def initialize(output)
|
11
|
+
@output = File.open(File.expand_path('../../../SPEC.md', __FILE__), 'w')
|
12
|
+
@indent = 0
|
13
|
+
@passed = 0
|
14
|
+
@pending = 0
|
15
|
+
@failed = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def start(notification)
|
19
|
+
puts "\n\e[33m --> Creating SPEC.md <--\e[0m\n"
|
20
|
+
output.write "# Ably Client Library #{Ably::VERSION} Specification\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
def close(notification)
|
24
|
+
output.close
|
25
|
+
end
|
26
|
+
|
27
|
+
def example_group_started(notification)
|
28
|
+
output.write "#{indent_prefix}#{notification.group.description}\n"
|
29
|
+
output.write "_(see #{heading_location_path(notification)})_\n" if indent == 0
|
30
|
+
@indent += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def example_group_finished(notification)
|
34
|
+
@indent -= 1
|
35
|
+
end
|
36
|
+
|
37
|
+
def example_passed(notification)
|
38
|
+
unless notification.example.metadata[:api_private]
|
39
|
+
output.write "#{indent_prefix}#{example_name_and_link(notification)}\n"
|
40
|
+
@passed += 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def example_failed(notification)
|
45
|
+
unless notification.example.metadata[:api_private]
|
46
|
+
output.write "#{indent_prefix}FAILED: ~~#{example_name_and_link(notification)}~~\n"
|
47
|
+
@failed += 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def example_pending(notification)
|
52
|
+
unless notification.example.metadata[:api_private]
|
53
|
+
output.write "#{indent_prefix}PENDING: *#{example_name_and_link(notification)}*\n"
|
54
|
+
@pending += 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def dump_summary(notification)
|
59
|
+
output.write <<-EOF.gsub(' ', '')
|
60
|
+
|
61
|
+
-------
|
62
|
+
|
63
|
+
## Test summary
|
64
|
+
|
65
|
+
* Passing tests: #{@passed}
|
66
|
+
* Pending tests: #{@pending}
|
67
|
+
* Failing tests: #{@failed}
|
68
|
+
EOF
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
attr_reader :output, :indent
|
73
|
+
|
74
|
+
def example_name_and_link(notification)
|
75
|
+
"[#{notification.example.metadata[:description]}](#{notification.example.location.gsub(/\:(\d+)/, '#L\1')})"
|
76
|
+
end
|
77
|
+
|
78
|
+
def heading_location_path(notification)
|
79
|
+
"[#{notification.group.location.gsub(/\:(\d+)/, '').gsub(%r{^.\/}, '')}](#{notification.group.location.gsub(/\:(\d+)/, '')})"
|
80
|
+
end
|
81
|
+
|
82
|
+
def indent_prefix
|
83
|
+
if indent > 0
|
84
|
+
"#{' ' * indent}* "
|
85
|
+
else
|
86
|
+
"\n### "
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
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
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module RSpec
|
2
|
+
module ProtocolHelper
|
3
|
+
PROTOCOLS = if ENV['TEST_LIMIT_PROTOCOLS']
|
4
|
+
JSON.parse(ENV['TEST_LIMIT_PROTOCOLS'])
|
5
|
+
else
|
6
|
+
{
|
7
|
+
json: 'JSON',
|
8
|
+
msgpack: 'MsgPack'
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def vary_by_protocol(&block)
|
13
|
+
RSpec::ProtocolHelper::PROTOCOLS.each do |protocol, description|
|
14
|
+
context("using #{description} protocol", protocol: protocol, &block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
RSpec.configure do |config|
|
21
|
+
config.extend RSpec::ProtocolHelper
|
22
|
+
|
23
|
+
config.before(:context, protocol: :json) do |context|
|
24
|
+
context.class.let(:protocol) { :json }
|
25
|
+
end
|
26
|
+
|
27
|
+
config.before(:context, protocol: :msgpack) do |context|
|
28
|
+
context.class.let(:protocol) { :msgpack }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module RandomHelper
|
4
|
+
def random_str(length = 16)
|
5
|
+
SecureRandom.hex(length).encode(Encoding::UTF_8)
|
6
|
+
end
|
7
|
+
|
8
|
+
def random_int_str(size = 1_000_000_000)
|
9
|
+
SecureRandom.random_number(size).to_s.encode(Encoding::UTF_8)
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.include self
|
14
|
+
end
|
15
|
+
end
|
data/spec/support/test_app.rb
CHANGED
@@ -90,6 +90,10 @@ class TestApp
|
|
90
90
|
@attributes = JSON.parse(response.body)
|
91
91
|
end
|
92
92
|
|
93
|
+
def host
|
94
|
+
sandbox_client.endpoint.host
|
95
|
+
end
|
96
|
+
|
93
97
|
private
|
94
98
|
def sandbox_client
|
95
99
|
@sandbox_client ||= Ably::Rest::Client.new(api_key: 'app.key:secret', tls: true, environment: environment)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'shared/protocol_msgbus_behaviour'
|
3
|
+
|
4
|
+
describe Ably::Auth do
|
5
|
+
let(:client) { double('client').as_null_object }
|
6
|
+
let(:client_id) { nil }
|
7
|
+
let(:options) { { api_key: 'appid.keyuid:keysecret', client_id: client_id } }
|
8
|
+
|
9
|
+
subject do
|
10
|
+
Ably::Auth.new(client, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'client_id option' do
|
14
|
+
let(:client_id) { random_str.encode(encoding) }
|
15
|
+
|
16
|
+
context 'with nil value' do
|
17
|
+
let(:client_id) { nil }
|
18
|
+
|
19
|
+
it 'is permitted' do
|
20
|
+
expect(subject.client_id).to be_nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'as UTF_8 string' do
|
25
|
+
let(:encoding) { Encoding::UTF_8 }
|
26
|
+
|
27
|
+
it 'is permitted' do
|
28
|
+
expect(subject.client_id).to eql(client_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'remains as UTF-8' do
|
32
|
+
expect(subject.client_id.encoding).to eql(encoding)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'as SHIFT_JIS string' do
|
37
|
+
let(:encoding) { Encoding::SHIFT_JIS }
|
38
|
+
|
39
|
+
it 'gets converted to UTF-8' do
|
40
|
+
expect(subject.client_id.encoding).to eql(Encoding::UTF_8)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'is compatible with original encoding' do
|
44
|
+
expect(subject.client_id.encode(encoding)).to eql(client_id)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'as ASCII_8BIT string' do
|
49
|
+
let(:encoding) { Encoding::ASCII_8BIT }
|
50
|
+
|
51
|
+
it 'gets converted to UTF-8' do
|
52
|
+
expect(subject.client_id.encoding).to eql(Encoding::UTF_8)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'is compatible with original encoding' do
|
56
|
+
expect(subject.client_id.encode(encoding)).to eql(client_id)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'as Integer' do
|
61
|
+
let(:client_id) { 1 }
|
62
|
+
|
63
|
+
it 'raises an argument error' do
|
64
|
+
expect { subject.client_id }.to raise_error ArgumentError, /must be a String/
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/unit/logger_spec.rb
CHANGED
@@ -1,96 +1,107 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Ably::Logger do
|
4
|
-
let(:new_client) do
|
5
|
-
instance_double('Ably::Realtime::Client', connection: instance_double('Ably::Realtime::Connection', id: nil))
|
6
|
-
end
|
7
|
-
let(:connected_client) do
|
8
|
-
instance_double('Ably::Realtime::Client', connection: instance_double('Ably::Realtime::Connection', id: '0000'))
|
9
|
-
end
|
10
4
|
let(:rest_client) do
|
11
5
|
instance_double('Ably::Rest::Client')
|
12
6
|
end
|
13
7
|
|
14
|
-
subject { Ably::Logger.new(
|
8
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO) }
|
15
9
|
|
16
10
|
def uncolorize(string)
|
17
11
|
regex_pattern = /\033\[[0-9]+m(.+?)\033\[0m/m
|
18
12
|
string.gsub(regex_pattern, '\1')
|
19
13
|
end
|
20
14
|
|
21
|
-
it 'uses the
|
15
|
+
it 'uses the language provided Logger by default' do
|
22
16
|
expect(subject.logger).to be_a(Logger)
|
23
17
|
end
|
24
18
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
19
|
+
context 'internals', :api_private do
|
20
|
+
it 'delegates to the logger object' do
|
21
|
+
expect(subject.logger).to receive(:warn).with('message')
|
22
|
+
subject.warn 'message'
|
23
|
+
end
|
29
24
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
context 'formatter' do
|
26
|
+
context 'when debugging' do
|
27
|
+
it 'uses short time format' do
|
28
|
+
formatted = subject.logger.formatter.call(Logger::DEBUG, Time.now, 'progid', 'unique_message')
|
29
|
+
formatted = uncolorize(formatted)
|
30
|
+
expect(formatted).to match(/^\d+:\d+:\d+.\d{3} DEBUG/)
|
31
|
+
end
|
36
32
|
end
|
37
|
-
end
|
38
33
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
34
|
+
context 'when info -> fatal' do
|
35
|
+
it 'uses long time format' do
|
36
|
+
formatted = subject.logger.formatter.call(Logger::INFO, Time.now, 'progid', 'unique_message')
|
37
|
+
formatted = uncolorize(formatted)
|
38
|
+
expect(formatted).to match(/^\d+-\d+-\d+ \d+:\d+:\d+.\d{3} INFO/)
|
39
|
+
end
|
44
40
|
end
|
45
|
-
end
|
46
41
|
|
47
|
-
|
48
|
-
|
42
|
+
if defined?(Ably::Realtime)
|
43
|
+
context 'with Realtime client' do
|
44
|
+
let(:new_realtime_client) do
|
45
|
+
instance_double('Ably::Realtime::Client', connection: instance_double('Ably::Realtime::Connection', id: nil))
|
46
|
+
end
|
47
|
+
let(:connected_realtime_client) do
|
48
|
+
instance_double('Ably::Realtime::Client', connection: instance_double('Ably::Realtime::Connection', id: '0000'))
|
49
|
+
end
|
50
|
+
before do
|
51
|
+
allow(new_realtime_client).to receive(:kind_of?).with(Ably::Realtime::Client).and_return(true)
|
52
|
+
allow(connected_realtime_client).to receive(:kind_of?).with(Ably::Realtime::Client).and_return(true)
|
53
|
+
end
|
49
54
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
context 'with Realtime disconnected client' do
|
56
|
+
subject { Ably::Logger.new(new_realtime_client, Logger::INFO) }
|
57
|
+
|
58
|
+
it 'formats logs with an empty client ID' do
|
59
|
+
formatted = subject.logger.formatter.call(Logger::DEBUG, Time.now, 'progid', 'unique_message')
|
60
|
+
formatted = uncolorize(formatted)
|
61
|
+
expect(formatted).to match(/\[ \-\- \]/)
|
62
|
+
expect(formatted).to match(%r{unique_message$})
|
63
|
+
expect(formatted).to match(%r{DEBUG})
|
64
|
+
end
|
65
|
+
end
|
58
66
|
|
59
|
-
|
60
|
-
|
67
|
+
context 'with Realtime connected client' do
|
68
|
+
subject { Ably::Logger.new(connected_realtime_client, Logger::INFO) }
|
61
69
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
70
|
+
it 'formats logs with a client ID' do
|
71
|
+
formatted = subject.logger.formatter.call(Logger::DEBUG, Time.now, 'progid', 'unique_message')
|
72
|
+
formatted = uncolorize(formatted)
|
73
|
+
expect(formatted).to match(/\[0000\]/)
|
74
|
+
expect(formatted).to match(%r{unique_message$})
|
75
|
+
expect(formatted).to match(%r{DEBUG})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
68
79
|
end
|
69
|
-
end
|
70
80
|
|
71
|
-
|
72
|
-
|
81
|
+
context 'with REST client' do
|
82
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO) }
|
73
83
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
84
|
+
it 'formats logs without a client ID' do
|
85
|
+
formatted = subject.logger.formatter.call(Logger::FATAL, Time.now, 'progid', 'unique_message')
|
86
|
+
formatted = uncolorize(formatted)
|
87
|
+
expect(formatted).to_not match(/\[.*\]/)
|
88
|
+
expect(formatted).to match(%r{unique_message$})
|
89
|
+
expect(formatted).to match(%r{FATAL})
|
90
|
+
end
|
80
91
|
end
|
81
|
-
end
|
82
92
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
93
|
+
context 'severity argument' do
|
94
|
+
it 'can be an Integer' do
|
95
|
+
formatted = subject.logger.formatter.call(Logger::INFO, Time.now, 'progid', 'unique_message')
|
96
|
+
formatted = uncolorize(formatted)
|
97
|
+
expect(formatted).to match(/^\d+-\d+-\d+ \d+:\d+:\d+.\d{3} INFO/)
|
98
|
+
end
|
89
99
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
100
|
+
it 'can be a string' do
|
101
|
+
formatted = subject.logger.formatter.call('INFO', Time.now, 'progid', 'unique_message')
|
102
|
+
formatted = uncolorize(formatted)
|
103
|
+
expect(formatted).to match(/^\d+-\d+-\d+ \d+:\d+:\d+.\d{3} INFO/)
|
104
|
+
end
|
94
105
|
end
|
95
106
|
end
|
96
107
|
end
|
@@ -100,7 +111,7 @@ describe Ably::Logger do
|
|
100
111
|
let(:custom_logger_with_bad_interface) do
|
101
112
|
Class.new.new
|
102
113
|
end
|
103
|
-
subject { Ably::Logger.new(
|
114
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO, custom_logger_with_bad_interface) }
|
104
115
|
|
105
116
|
it 'raises an exception' do
|
106
117
|
expect { subject }.to raise_error ArgumentError, /The custom Logger's interface does not provide the method/
|
@@ -119,14 +130,14 @@ describe Ably::Logger do
|
|
119
130
|
end
|
120
131
|
let(:custom_logger_object) { custom_logger.new }
|
121
132
|
|
122
|
-
subject { Ably::Logger.new(
|
133
|
+
subject { Ably::Logger.new(rest_client, Logger::INFO, custom_logger_object) }
|
123
134
|
|
124
135
|
it 'is used' do
|
125
136
|
expect { subject }.to_not raise_error
|
126
137
|
expect(subject.logger.class).to eql(custom_logger)
|
127
138
|
end
|
128
139
|
|
129
|
-
it 'delegates log messages to logger' do
|
140
|
+
it 'delegates log messages to logger', :api_private do
|
130
141
|
expect(custom_logger_object).to receive(:fatal).with('message')
|
131
142
|
subject.fatal 'message'
|
132
143
|
end
|