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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.ruby-version.old +1 -0
  4. data/.travis.yml +0 -2
  5. data/Rakefile +22 -4
  6. data/SPEC.md +1676 -0
  7. data/ably.gemspec +1 -1
  8. data/lib/ably.rb +0 -8
  9. data/lib/ably/auth.rb +54 -46
  10. data/lib/ably/exceptions.rb +19 -5
  11. data/lib/ably/logger.rb +1 -1
  12. data/lib/ably/models/error_info.rb +1 -1
  13. data/lib/ably/models/idiomatic_ruby_wrapper.rb +11 -9
  14. data/lib/ably/models/message.rb +15 -12
  15. data/lib/ably/models/message_encoders/base.rb +6 -5
  16. data/lib/ably/models/message_encoders/base64.rb +1 -0
  17. data/lib/ably/models/message_encoders/cipher.rb +6 -3
  18. data/lib/ably/models/message_encoders/json.rb +1 -0
  19. data/lib/ably/models/message_encoders/utf8.rb +2 -9
  20. data/lib/ably/models/nil_logger.rb +20 -0
  21. data/lib/ably/models/paginated_resource.rb +5 -2
  22. data/lib/ably/models/presence_message.rb +21 -12
  23. data/lib/ably/models/protocol_message.rb +22 -6
  24. data/lib/ably/modules/ably.rb +11 -0
  25. data/lib/ably/modules/async_wrapper.rb +2 -0
  26. data/lib/ably/modules/conversions.rb +23 -3
  27. data/lib/ably/modules/encodeable.rb +2 -1
  28. data/lib/ably/modules/enum.rb +2 -0
  29. data/lib/ably/modules/event_emitter.rb +7 -1
  30. data/lib/ably/modules/event_machine_helpers.rb +2 -0
  31. data/lib/ably/modules/http_helpers.rb +2 -0
  32. data/lib/ably/modules/model_common.rb +12 -2
  33. data/lib/ably/modules/state_emitter.rb +76 -0
  34. data/lib/ably/modules/state_machine.rb +53 -0
  35. data/lib/ably/modules/statesman_monkey_patch.rb +33 -0
  36. data/lib/ably/modules/uses_state_machine.rb +74 -0
  37. data/lib/ably/realtime.rb +4 -2
  38. data/lib/ably/realtime/channel.rb +51 -58
  39. data/lib/ably/realtime/channel/channel_manager.rb +91 -0
  40. data/lib/ably/realtime/channel/channel_state_machine.rb +68 -0
  41. data/lib/ably/realtime/client.rb +70 -26
  42. data/lib/ably/realtime/client/incoming_message_dispatcher.rb +31 -13
  43. data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +1 -1
  44. data/lib/ably/realtime/connection.rb +135 -92
  45. data/lib/ably/realtime/connection/connection_manager.rb +216 -33
  46. data/lib/ably/realtime/connection/connection_state_machine.rb +30 -73
  47. data/lib/ably/realtime/models/nil_channel.rb +10 -1
  48. data/lib/ably/realtime/presence.rb +336 -92
  49. data/lib/ably/rest.rb +2 -2
  50. data/lib/ably/rest/channel.rb +13 -4
  51. data/lib/ably/rest/client.rb +138 -38
  52. data/lib/ably/rest/middleware/logger.rb +24 -3
  53. data/lib/ably/rest/presence.rb +12 -7
  54. data/lib/ably/version.rb +1 -1
  55. data/spec/acceptance/realtime/channel_history_spec.rb +101 -85
  56. data/spec/acceptance/realtime/channel_spec.rb +461 -120
  57. data/spec/acceptance/realtime/client_spec.rb +119 -0
  58. data/spec/acceptance/realtime/connection_failures_spec.rb +499 -0
  59. data/spec/acceptance/realtime/connection_spec.rb +571 -97
  60. data/spec/acceptance/realtime/message_spec.rb +347 -333
  61. data/spec/acceptance/realtime/presence_history_spec.rb +35 -40
  62. data/spec/acceptance/realtime/presence_spec.rb +769 -239
  63. data/spec/acceptance/realtime/stats_spec.rb +14 -22
  64. data/spec/acceptance/realtime/time_spec.rb +16 -20
  65. data/spec/acceptance/rest/auth_spec.rb +425 -364
  66. data/spec/acceptance/rest/base_spec.rb +108 -176
  67. data/spec/acceptance/rest/channel_spec.rb +89 -89
  68. data/spec/acceptance/rest/channels_spec.rb +30 -32
  69. data/spec/acceptance/rest/client_spec.rb +273 -0
  70. data/spec/acceptance/rest/encoders_spec.rb +185 -0
  71. data/spec/acceptance/rest/message_spec.rb +186 -163
  72. data/spec/acceptance/rest/presence_spec.rb +150 -111
  73. data/spec/acceptance/rest/stats_spec.rb +45 -40
  74. data/spec/acceptance/rest/time_spec.rb +8 -10
  75. data/spec/rspec_config.rb +10 -1
  76. data/spec/shared/client_initializer_behaviour.rb +212 -0
  77. data/spec/{support/model_helper.rb → shared/model_behaviour.rb} +6 -6
  78. data/spec/{support/protocol_msgbus_helper.rb → shared/protocol_msgbus_behaviour.rb} +1 -1
  79. data/spec/spec_helper.rb +9 -0
  80. data/spec/support/api_helper.rb +11 -0
  81. data/spec/support/event_machine_helper.rb +101 -3
  82. data/spec/support/markdown_spec_formatter.rb +90 -0
  83. data/spec/support/private_api_formatter.rb +36 -0
  84. data/spec/support/protocol_helper.rb +32 -0
  85. data/spec/support/random_helper.rb +15 -0
  86. data/spec/support/test_app.rb +4 -0
  87. data/spec/unit/auth_spec.rb +68 -0
  88. data/spec/unit/logger_spec.rb +77 -66
  89. data/spec/unit/models/error_info_spec.rb +1 -1
  90. data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +2 -3
  91. data/spec/unit/models/message_encoders/base64_spec.rb +2 -2
  92. data/spec/unit/models/message_encoders/cipher_spec.rb +2 -2
  93. data/spec/unit/models/message_encoders/utf8_spec.rb +2 -46
  94. data/spec/unit/models/message_spec.rb +160 -15
  95. data/spec/unit/models/paginated_resource_spec.rb +29 -27
  96. data/spec/unit/models/presence_message_spec.rb +163 -20
  97. data/spec/unit/models/protocol_message_spec.rb +43 -8
  98. data/spec/unit/modules/async_wrapper_spec.rb +2 -3
  99. data/spec/unit/modules/conversions_spec.rb +1 -1
  100. data/spec/unit/modules/enum_spec.rb +2 -3
  101. data/spec/unit/modules/event_emitter_spec.rb +62 -5
  102. data/spec/unit/modules/state_emitter_spec.rb +283 -0
  103. data/spec/unit/realtime/channel_spec.rb +107 -2
  104. data/spec/unit/realtime/channels_spec.rb +1 -0
  105. data/spec/unit/realtime/client_spec.rb +8 -48
  106. data/spec/unit/realtime/connection_spec.rb +3 -3
  107. data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +2 -2
  108. data/spec/unit/realtime/presence_spec.rb +13 -4
  109. data/spec/unit/realtime/realtime_spec.rb +0 -11
  110. data/spec/unit/realtime/websocket_transport_spec.rb +2 -2
  111. data/spec/unit/rest/channel_spec.rb +109 -0
  112. data/spec/unit/rest/channels_spec.rb +4 -3
  113. data/spec/unit/rest/client_spec.rb +30 -125
  114. data/spec/unit/rest/rest_spec.rb +10 -0
  115. data/spec/unit/util/crypto_spec.rb +10 -5
  116. data/spec/unit/util/pub_sub_spec.rb +5 -5
  117. metadata +44 -12
  118. data/spec/integration/modules/state_emitter_spec.rb +0 -80
  119. data/spec/integration/rest/auth.rb +0 -9
@@ -1,55 +1,60 @@
1
+ # encoding: utf-8
1
2
  require 'spec_helper'
2
- require 'securerandom'
3
-
4
- describe 'Ably::Rest::Client Stats' do
5
- [:json, :msgpack].each do |protocol|
6
- context "over #{protocol}" do
7
- describe 'fetching application stats' do
8
- before(:context) do
9
- reload_test_app
10
- end
11
3
 
12
- def number_of_channels() 3 end
13
- def number_of_messages_per_channel() 5 end
4
+ describe Ably::Rest::Client, '#stats' do
5
+ before(:context) do
6
+ WebMock.disable! # ensure previous test's WebMock does not have side effects
7
+ reload_test_app
8
+ end
14
9
 
15
- before(:context) do
16
- @context_client = Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol)
10
+ before(:context) do
11
+ client = Ably::Rest::Client.new(api_key: api_key, environment: environment)
17
12
 
18
- # Wait until the start of the next minute according to the service
19
- # time because stats are created in 1 minute intervals
20
- service_time = @context_client.time
21
- @interval_start = (service_time.to_i / 60 + 1) * 60
22
- sleep_time = @interval_start - Time.now.to_i
13
+ number_of_channels = 3
14
+ number_of_messages_per_channel = 5
23
15
 
24
- if sleep_time > 30
25
- @interval_start -= 60 # there is enough time to generate the stats in this minute interval
26
- elsif sleep_time > 0
27
- sleep sleep_time
28
- end
16
+ # Wait until the start of the next minute according to the service
17
+ # time because stats are created in 1 minute intervals
18
+ service_time = client.time
19
+ stats_setup_at = (service_time.to_i / 60 + 1) * 60
20
+ sleep_time = stats_setup_at - Time.now.to_i
29
21
 
30
- number_of_channels.times do |i|
31
- channel = @context_client.channel("stats-#{i}")
22
+ if sleep_time > 30
23
+ stats_setup_at -= 60 # there is enough time to generate the stats in this minute interval
24
+ elsif sleep_time > 0
25
+ sleep sleep_time
26
+ end
32
27
 
33
- number_of_messages_per_channel.times do |j|
34
- channel.publish("event-#{j}", "data-#{j}") || raise("Unable to publish message")
35
- end
36
- end
28
+ number_of_channels.times do |i|
29
+ channel = client.channel("stats-#{i}")
37
30
 
38
- sleep(10)
39
- end
31
+ number_of_messages_per_channel.times do |j|
32
+ channel.publish("event-#{j}", "data-#{j}") || raise("Unable to publish message")
33
+ end
34
+ end
35
+
36
+ # wait for stats to be persisted
37
+ sleep 10
38
+
39
+ @stats_setup_at = stats_setup_at
40
+ @messages_published_count = number_of_channels * number_of_messages_per_channel
41
+ end
40
42
 
41
- [:minute, :hour, :day, :month].each do |interval|
42
- context "by #{interval}" do
43
- it 'should return all the stats for the application' do
44
- stats = @context_client.stats(start: @interval_start * 1000, by: interval.to_s, direction: 'forwards')
43
+ vary_by_protocol do
44
+ describe 'fetching application stats' do
45
+ [:minute, :hour, :day, :month].each do |interval|
46
+ context "by #{interval}" do
47
+ let(:client) { Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol) }
45
48
 
46
- expect(stats.size).to eql(1)
49
+ it 'should return all the stats for the application' do
50
+ stats = client.stats(start: @stats_setup_at * 1000, by: interval.to_s, direction: 'forwards')
47
51
 
48
- stat = stats.first
52
+ expect(stats.size).to eql(1)
53
+ stat = stats.first
49
54
 
50
- expect(stat[:inbound][:all][:messages][:count]).to eql(number_of_channels * number_of_messages_per_channel)
51
- expect(stat[:inbound][:rest][:messages][:count]).to eql(number_of_channels * number_of_messages_per_channel)
52
- end
55
+ expect(@messages_published_count).to be_a(Numeric)
56
+ expect(stat[:inbound][:all][:messages][:count]).to eql(@messages_published_count)
57
+ expect(stat[:inbound][:rest][:messages][:count]).to eql(@messages_published_count)
53
58
  end
54
59
  end
55
60
  end
@@ -1,16 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Ably::REST::Client time' do
4
- [:msgpack, :json].each do |protocol|
5
- context "over #{protocol}" do
6
- let(:client) do
7
- Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol)
8
- end
3
+ describe Ably::Rest::Client, '#time' do
4
+ vary_by_protocol do
5
+ let(:client) do
6
+ Ably::Rest::Client.new(api_key: api_key, environment: environment, protocol: protocol)
7
+ end
9
8
 
10
- describe 'fetching the service time' do
11
- it 'should return the service time as a Time object' do
12
- expect(client.time).to be_within(2).of(Time.now)
13
- end
9
+ describe 'fetching the service time' do
10
+ it 'should return the service time as a Time object' do
11
+ expect(client.time).to be_within(2).of(Time.now)
14
12
  end
15
13
  end
16
14
  end
@@ -27,7 +27,7 @@ RSpec.configure do |config|
27
27
  WebMock.disable!
28
28
  end
29
29
 
30
- config.before(:example, :webmock => true) do
30
+ config.before(:example, :webmock) do
31
31
  allow(TestApp).to receive(:instance).and_return(instance_double('TestApp',
32
32
  app_id: 'app_id',
33
33
  key_id: 'app_id.key_id',
@@ -36,4 +36,13 @@ RSpec.configure do |config|
36
36
  ))
37
37
  WebMock.enable!
38
38
  end
39
+
40
+ if defined?(EventMachine)
41
+ config.before(:example) do
42
+ # Ensure EventMachine shutdown hooks are deregistered for every test
43
+ EventMachine.instance_variable_set '@tails', []
44
+ end
45
+ end
46
+
47
+ config.add_formatter Ably::RSpec::PrivateApiFormatter
39
48
  end
@@ -0,0 +1,212 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples 'a client initializer' do
4
+ def subdomain
5
+ if rest?
6
+ 'rest'
7
+ else
8
+ 'realtime'
9
+ end
10
+ end
11
+
12
+ def protocol
13
+ if rest?
14
+ 'http'
15
+ else
16
+ 'ws'
17
+ end
18
+ end
19
+
20
+ def rest?
21
+ subject.kind_of?(Ably::Rest::Client)
22
+ end
23
+
24
+ context 'with invalid arguments' do
25
+ context 'empty hash' do
26
+ let(:client_options) { Hash.new }
27
+
28
+ it 'raises an exception' do
29
+ expect { subject }.to raise_error(ArgumentError, /api_key is missing/)
30
+ end
31
+ end
32
+
33
+ context 'nil' do
34
+ let(:client_options) { nil }
35
+
36
+ it 'raises an exception' do
37
+ expect { subject }.to raise_error(ArgumentError, /Options Hash is expected/)
38
+ end
39
+ end
40
+
41
+ context 'api_key: "invalid"' do
42
+ let(:client_options) { { api_key: 'invalid' } }
43
+
44
+ it 'raises an exception' do
45
+ expect { subject }.to raise_error(ArgumentError, /api_key is invalid/)
46
+ end
47
+ end
48
+
49
+ context 'api_key: "invalid:asdad"' do
50
+ let(:client_options) { { api_key: 'invalid:asdad' } }
51
+
52
+ it 'raises an exception' do
53
+ expect { subject }.to raise_error(ArgumentError, /api_key is invalid/)
54
+ end
55
+ end
56
+
57
+ context 'api_key and key_id' do
58
+ let(:client_options) { { api_key: 'appid.keyuid:keysecret', key_id: 'invalid' } }
59
+
60
+ it 'raises an exception' do
61
+ expect { subject }.to raise_error(ArgumentError, /api_key and key_id or key_secret are mutually exclusive/)
62
+ end
63
+ end
64
+
65
+ context 'api_key and key_secret' do
66
+ let(:client_options) { { api_key: 'appid.keyuid:keysecret', key_secret: 'invalid' } }
67
+
68
+ it 'raises an exception' do
69
+ expect { subject }.to raise_error(ArgumentError, /api_key and key_id or key_secret are mutually exclusive/)
70
+ end
71
+ end
72
+
73
+ context 'client_id as only option' do
74
+ let(:client_options) { { client_id: 'valid' } }
75
+
76
+ it 'requires a valid key' do
77
+ expect { subject }.to raise_error(ArgumentError, /client_id cannot be provided without a complete API key/)
78
+ end
79
+ end
80
+ end
81
+
82
+ context 'with valid arguments' do
83
+ let(:default_options) { { api_key: 'appid.keyuid:keysecret' } }
84
+ let(:client_options) { default_options }
85
+
86
+ context 'api_key only' do
87
+ it 'connects to the Ably service' do
88
+ expect { subject }.to_not raise_error
89
+ end
90
+ end
91
+
92
+ context 'key_id and key_secret' do
93
+ let(:client_options) { { key_id: 'id', key_secret: 'secret' } }
94
+
95
+ it 'constructs an api_key' do
96
+ expect(subject.auth.api_key).to eql('id:secret')
97
+ end
98
+ end
99
+
100
+ context 'with a string key instead of options hash' do
101
+ let(:client_options) { 'app.key:secret' }
102
+
103
+ it 'sets the api_key' do
104
+ expect(subject.auth.api_key).to eql(client_options)
105
+ end
106
+
107
+ it 'sets the key_id' do
108
+ expect(subject.auth.key_id).to eql('app.key')
109
+ end
110
+
111
+ it 'sets the key_secret' do
112
+ expect(subject.auth.key_secret).to eql('secret')
113
+ end
114
+ end
115
+
116
+ context 'with token' do
117
+ let(:client_options) { { token_id: 'token' } }
118
+
119
+ it 'sets the token_id' do
120
+ expect(subject.auth.token_id).to eql('token')
121
+ end
122
+ end
123
+
124
+ context 'endpoint' do
125
+ it 'defaults to production' do
126
+ expect(subject.endpoint.to_s).to eql("#{protocol}s://#{subdomain}.ably.io")
127
+ end
128
+
129
+ context 'with environment option' do
130
+ let(:client_options) { default_options.merge(environment: 'sandbox') }
131
+
132
+ it 'uses an alternate endpoint' do
133
+ expect(subject.endpoint.to_s).to eql("#{protocol}s://sandbox-#{subdomain}.ably.io")
134
+ end
135
+ end
136
+ end
137
+
138
+ context 'tls' do
139
+ context 'set to false' do
140
+ let(:client_options) { default_options.merge(tls: false) }
141
+
142
+ it 'uses plain text' do
143
+ expect(subject.use_tls?).to eql(false)
144
+ end
145
+
146
+ it 'uses HTTP' do
147
+ expect(subject.endpoint.to_s).to eql("#{protocol}://#{subdomain}.ably.io")
148
+ end
149
+ end
150
+
151
+ it 'defaults to TLS' do
152
+ expect(subject.use_tls?).to eql(true)
153
+ end
154
+ end
155
+
156
+ context 'logger' do
157
+ context 'default' do
158
+ it 'uses Ruby Logger' do
159
+ expect(subject.logger.logger).to be_a(::Logger)
160
+ end
161
+
162
+ it 'specifies Logger::ERROR log level' do
163
+ expect(subject.logger.log_level).to eql(::Logger::ERROR)
164
+ end
165
+ end
166
+
167
+ context 'with log_level :none' do
168
+ let(:client_options) { default_options.merge(log_level: :none) }
169
+
170
+ it 'silences all logging with a NilLogger' do
171
+ expect(subject.logger.logger.class).to eql(Ably::Models::NilLogger)
172
+ expect(subject.logger.log_level).to eql(:none)
173
+ end
174
+ end
175
+
176
+ context 'with custom logger and log_level' do
177
+ let(:custom_logger) do
178
+ Class.new do
179
+ extend Forwardable
180
+ def initialize
181
+ @logger = Logger.new(STDOUT)
182
+ end
183
+ def_delegators :@logger, :fatal, :error, :warn, :info, :debug, :level, :level=
184
+ end
185
+ end
186
+ let(:client_options) { default_options.merge(logger: custom_logger.new, log_level: Logger::DEBUG) }
187
+
188
+ it 'uses the custom logger' do
189
+ expect(subject.logger.logger.class).to eql(custom_logger)
190
+ end
191
+
192
+ it 'sets the custom log level' do
193
+ expect(subject.logger.log_level).to eql(Logger::DEBUG)
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ context 'delegators' do
200
+ let(:client_options) { 'app.key:secret' }
201
+
202
+ it 'delegates :client_id to .auth' do
203
+ expect(subject.auth).to receive(:client_id).and_return('john')
204
+ expect(subject.client_id).to eql('john')
205
+ end
206
+
207
+ it 'delegates :auth_options to .auth' do
208
+ expect(subject.auth).to receive(:auth_options).and_return({ option: 1 })
209
+ expect(subject.auth_options).to eql({ option: 1 })
210
+ end
211
+ end
212
+ end
@@ -1,4 +1,4 @@
1
- require 'securerandom'
1
+ # encoding: utf-8
2
2
 
3
3
  shared_examples 'a model' do |shared_options = {}|
4
4
  let(:base_model_options) { shared_options.fetch(:base_model_options, {}) }
@@ -6,7 +6,7 @@ shared_examples 'a model' do |shared_options = {}|
6
6
  let(:model) { subject.new(*args) }
7
7
 
8
8
  context 'attributes' do
9
- let(:unique_value) { SecureRandom.hex }
9
+ let(:unique_value) { random_str }
10
10
 
11
11
  Array(shared_options[:with_simple_attributes]).each do |attribute|
12
12
  context "##{attribute}" do
@@ -18,7 +18,7 @@ shared_examples 'a model' do |shared_options = {}|
18
18
  end
19
19
  end
20
20
 
21
- context '#hash' do
21
+ context '#hash', :api_private do
22
22
  let(:model_options) { { action: 5 } }
23
23
 
24
24
  it 'provides access to #hash' do
@@ -26,7 +26,7 @@ shared_examples 'a model' do |shared_options = {}|
26
26
  end
27
27
  end
28
28
 
29
- context '#[]' do
29
+ context '#[]', :api_private do
30
30
  let(:model_options) { { unusual: 'attribute' } }
31
31
 
32
32
  it 'provides accessor method to #hash' do
@@ -52,7 +52,7 @@ shared_examples 'a model' do |shared_options = {}|
52
52
  end
53
53
  end
54
54
 
55
- context '#to_msgpack' do
55
+ context '#to_msgpack', :api_private do
56
56
  let(:model_options) { { name: 'test', action: 0, channel_snake_case: 'unique' } }
57
57
  let(:serialized) { model.to_msgpack }
58
58
 
@@ -61,7 +61,7 @@ shared_examples 'a model' do |shared_options = {}|
61
61
  end
62
62
  end
63
63
 
64
- context '#to_json' do
64
+ context '#to_json', :api_private do
65
65
  let(:model_options) { { name: 'test', action: 0, channel_snake_case: 'unique' } }
66
66
  let(:serialized) { model.to_json }
67
67
 
@@ -1,5 +1,5 @@
1
1
  shared_examples 'a protocol message bus' do
2
- describe '__protocol_msgbus__ PubSub' do
2
+ describe '__protocol_msgbus__ PubSub', :api_private do
3
3
  let(:protocol_message) do
4
4
  Ably::Models::ProtocolMessage.new(
5
5
  action: 15,
@@ -1,8 +1,17 @@
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
+
1
7
  require 'webmock/rspec'
2
8
 
3
9
  require 'ably'
4
10
 
5
11
  require 'support/api_helper'
6
12
  require 'support/event_machine_helper'
13
+ require 'support/private_api_formatter'
14
+ require 'support/protocol_helper'
15
+ require 'support/random_helper'
7
16
 
8
17
  require 'rspec_config'
@@ -46,3 +46,14 @@ RSpec.configure do |config|
46
46
  TestApp.instance.delete if TestApp.instance_variable_get('@singleton__instance__')
47
47
  end
48
48
  end
49
+
50
+ module ApiPreloader
51
+ def self.included(mod)
52
+ WebMock.disable!
53
+ TestApp.instance.api_key
54
+ end
55
+
56
+ RSpec.configure do |config|
57
+ config.include self, :file_path => %r(spec/acceptance)
58
+ end
59
+ end