ably 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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