em-twitter 0.1.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.
- data/.gemtest +0 -0
- data/.gitignore +40 -0
- data/.rspec +3 -0
- data/.simplecov +1 -0
- data/.travis.yml +8 -0
- data/.yardopts +3 -0
- data/Gemfile +7 -0
- data/Guardfile +6 -0
- data/LICENSE.md +20 -0
- data/README.md +117 -0
- data/Rakefile +15 -0
- data/em-twitter.gemspec +31 -0
- data/examples/stream.rb +61 -0
- data/lib/em-twitter.rb +35 -0
- data/lib/em-twitter/client.rb +111 -0
- data/lib/em-twitter/connection.rb +273 -0
- data/lib/em-twitter/decoders/base_decoder.rb +11 -0
- data/lib/em-twitter/decoders/gzip_decoder.rb +14 -0
- data/lib/em-twitter/proxy.rb +25 -0
- data/lib/em-twitter/reconnectors/application_failure.rb +50 -0
- data/lib/em-twitter/reconnectors/network_failure.rb +51 -0
- data/lib/em-twitter/request.rb +126 -0
- data/lib/em-twitter/response.rb +48 -0
- data/lib/em-twitter/version.rb +5 -0
- data/lib/em_twitter.rb +1 -0
- data/smoke.rb +66 -0
- data/spec/em-twitter/client_spec.rb +55 -0
- data/spec/em-twitter/connection_error_handling_spec.rb +12 -0
- data/spec/em-twitter/connection_reconnect_spec.rb +139 -0
- data/spec/em-twitter/connection_spec.rb +148 -0
- data/spec/em-twitter/decoders/base_decoder_spec.rb +15 -0
- data/spec/em-twitter/decoders/gzip_decoder_spec.rb +20 -0
- data/spec/em-twitter/proxy_spec.rb +23 -0
- data/spec/em-twitter/reconnectors/application_failure_spec.rb +74 -0
- data/spec/em-twitter/reconnectors/network_failure_spec.rb +80 -0
- data/spec/em-twitter/request_spec.rb +77 -0
- data/spec/em-twitter/response_spec.rb +89 -0
- data/spec/em_twitter_spec.rb +19 -0
- data/spec/spec_helper.rb +68 -0
- metadata +207 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EM::Twitter::BaseDecoder do
|
4
|
+
|
5
|
+
describe '#decode' do
|
6
|
+
before do
|
7
|
+
@decoder = EM::Twitter::BaseDecoder.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'passes through the response data' do
|
11
|
+
@decoder.decode('abc').should eq('abc')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EM::Twitter::GzipDecoder do
|
4
|
+
|
5
|
+
describe '#decode' do
|
6
|
+
before do
|
7
|
+
@decoder = EM::Twitter::GzipDecoder.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'decodes the response data' do
|
11
|
+
output = StringIO.new
|
12
|
+
gz = Zlib::GzipWriter.new(output)
|
13
|
+
gz.write('abc')
|
14
|
+
gz.close
|
15
|
+
|
16
|
+
@decoder.decode(output.string).should eq('abc')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EM::Twitter::Proxy do
|
4
|
+
describe '.new' do
|
5
|
+
it 'interprets a proxy configuration' do
|
6
|
+
proxy = EM::Twitter::Proxy.new(proxy_options[:proxy])
|
7
|
+
proxy.user.should eq('username')
|
8
|
+
proxy.password.should eq('password')
|
9
|
+
proxy.uri.should eq('http://my-proxy:8080')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#header' do
|
14
|
+
it 'returns false when no proxy credentials are passed' do
|
15
|
+
EM::Twitter::Proxy.new.header.should be_false
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'generates a header when passed credentials' do
|
19
|
+
proxy = EM::Twitter::Proxy.new(proxy_options[:proxy])
|
20
|
+
proxy.header.should be
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include EM::Twitter::Reconnectors
|
4
|
+
|
5
|
+
describe EM::Twitter::Reconnectors::ApplicationFailure do
|
6
|
+
describe 'initialization' do
|
7
|
+
it 'initializes the reconnect_timeout' do
|
8
|
+
reconn = ApplicationFailure.new
|
9
|
+
reconn.reconnect_timeout.should eq(ApplicationFailure::START)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'accepts an options hash' do
|
13
|
+
reconn = ApplicationFailure.new(:reconnect_count => 25)
|
14
|
+
reconn.reconnect_count.should eq(25)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'reconnect_timeout' do
|
19
|
+
it 'returns the reconnect_timeout' do
|
20
|
+
reconn = ApplicationFailure.new
|
21
|
+
reconn.reconnect_timeout = 12
|
22
|
+
reconn.reconnect_timeout.should eq(12)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#increment' do
|
27
|
+
it 'increments the reconnect_count' do
|
28
|
+
reconn = ApplicationFailure.new
|
29
|
+
reconn.increment
|
30
|
+
reconn.reconnect_count.should eq(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'increments the reconnect_timeout' do
|
34
|
+
reconn = ApplicationFailure.new
|
35
|
+
reconn.increment
|
36
|
+
reconn.reconnect_timeout.should eq(20)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'accepts a block and yields the current timeout' do
|
40
|
+
recon_timeout = 0
|
41
|
+
|
42
|
+
reconn = ApplicationFailure.new
|
43
|
+
reconn.increment do |timeout|
|
44
|
+
recon_timeout = timeout
|
45
|
+
end
|
46
|
+
|
47
|
+
recon_timeout.should eq(20)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises an ReconnectLimitError after exceeding max reconnects' do
|
51
|
+
lambda {
|
52
|
+
reconn = ApplicationFailure.new(:reconnect_count => 11)
|
53
|
+
reconn.increment
|
54
|
+
}.should raise_error(EventMachine::Twitter::ReconnectLimitError)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'raises an ReconnectLimitError after exceeding the reconnect time limit' do
|
58
|
+
lambda {
|
59
|
+
reconn = ApplicationFailure.new(:reconnect_timeout => 321)
|
60
|
+
reconn.increment
|
61
|
+
}.should raise_error(EventMachine::Twitter::ReconnectLimitError)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#reset' do
|
66
|
+
it 'resets the reconnect_count' do
|
67
|
+
reconn = ApplicationFailure.new(:reconnect_count => 25)
|
68
|
+
reconn.reconnect_count.should eq(25)
|
69
|
+
|
70
|
+
reconn.reset
|
71
|
+
reconn.reconnect_count.should be_zero
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include EM::Twitter::Reconnectors
|
4
|
+
|
5
|
+
describe EM::Twitter::Reconnectors::NetworkFailure do
|
6
|
+
describe 'initialization' do
|
7
|
+
it 'initializes the reconnect_timeout' do
|
8
|
+
reconn = NetworkFailure.new
|
9
|
+
reconn.reconnect_timeout.should eq(NetworkFailure::START)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'accepts an options hash' do
|
13
|
+
reconn = NetworkFailure.new(:reconnect_count => 25)
|
14
|
+
reconn.reconnect_count.should eq(25)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'reconnect_timeout' do
|
19
|
+
it 'returns the reconnect_timeout' do
|
20
|
+
reconn = NetworkFailure.new
|
21
|
+
reconn.reconnect_timeout = 12
|
22
|
+
reconn.reconnect_timeout.should eq(12)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'returns the maximum timeout when greater than the max' do
|
26
|
+
reconn = NetworkFailure.new
|
27
|
+
reconn.reconnect_timeout = NetworkFailure::MAX + 2
|
28
|
+
reconn.reconnect_timeout.should eq(NetworkFailure::MAX)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#increment' do
|
33
|
+
it 'increments the reconnect_count' do
|
34
|
+
reconn = NetworkFailure.new
|
35
|
+
reconn.increment
|
36
|
+
reconn.reconnect_count.should eq(1)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'increments the reconnect_timeout' do
|
40
|
+
reconn = NetworkFailure.new
|
41
|
+
reconn.increment
|
42
|
+
reconn.reconnect_timeout.should eq(0.5)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'accepts a block and yields the current timeout' do
|
46
|
+
recon_timeout = 0
|
47
|
+
|
48
|
+
reconn = NetworkFailure.new
|
49
|
+
reconn.increment do |timeout|
|
50
|
+
recon_timeout = timeout
|
51
|
+
end
|
52
|
+
|
53
|
+
recon_timeout.should eq(0.5)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'raises an ReconnectLimitError after exceeding max reconnects' do
|
57
|
+
lambda {
|
58
|
+
reconn = NetworkFailure.new(:reconnect_count => 11)
|
59
|
+
reconn.increment
|
60
|
+
}.should raise_error(EventMachine::Twitter::ReconnectLimitError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'raises an ReconnectLimitError after exceeding the reconnect time limit' do
|
64
|
+
lambda {
|
65
|
+
reconn = NetworkFailure.new(:reconnect_timeout => 321)
|
66
|
+
reconn.increment
|
67
|
+
}.should raise_error(EventMachine::Twitter::ReconnectLimitError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#reset' do
|
72
|
+
it 'resets the reconnect_count' do
|
73
|
+
reconn = NetworkFailure.new(:reconnect_count => 25)
|
74
|
+
reconn.reconnect_count.should eq(25)
|
75
|
+
|
76
|
+
reconn.reset
|
77
|
+
reconn.reconnect_count.should be_zero
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EM::Twitter::Request do
|
4
|
+
describe '.new' do
|
5
|
+
it 'assigns a proxy if one is set' do
|
6
|
+
req = EM::Twitter::Request.new(proxy_options)
|
7
|
+
req.proxy.should be
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'overrides defaults' do
|
11
|
+
req = EM::Twitter::Request.new(default_options)
|
12
|
+
req.options[:path].should eq('/1/statuses/filter.json')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#proxy?' do
|
17
|
+
it 'defaults to false' do
|
18
|
+
req = EM::Twitter::Request.new
|
19
|
+
req.proxy?.should be_false
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns true when a proxy is set' do
|
23
|
+
req = EM::Twitter::Request.new(proxy_options)
|
24
|
+
req.proxy?.should be_true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#to_s' do
|
29
|
+
context 'without a proxy' do
|
30
|
+
before do
|
31
|
+
@request = EM::Twitter::Request.new(default_options)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'requests the defined path' do
|
35
|
+
@request.to_s.should include('/1/statuses/filter.json')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'includes an OAuth header' do
|
39
|
+
@request.to_s.should include('Authorization: OAuth')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when using a proxy' do
|
44
|
+
before do
|
45
|
+
@request = EM::Twitter::Request.new(default_options.merge(proxy_options))
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'requests the full uri' do
|
49
|
+
@request.to_s.should include("POST http://#{test_options[:host]}:#{test_options[:port]}/1/statuses/filter.json")
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'includes a Proxy header' do
|
53
|
+
@request.to_s.should include('Proxy-Authorization: Basic ')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'adds a POST body' do
|
58
|
+
@request = EM::Twitter::Request.new(default_options)
|
59
|
+
@request.to_s.should include('track=nfl')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'adds query parameters' do
|
63
|
+
@request = EM::Twitter::Request.new(default_options.merge(:method => :get))
|
64
|
+
@request.to_s.should include('/1/statuses/filter.json?track=nfl')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'allows defining a custom user-agent' do
|
68
|
+
@request = EM::Twitter::Request.new(default_options.merge(:user_agent => 'EM::Twitter Test Suite'))
|
69
|
+
@request.to_s.should include('User-Agent: EM::Twitter Test Suite')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'adds custom headers' do
|
73
|
+
@request = EM::Twitter::Request.new(default_options.merge(:headers => { 'foo' => 'bar'}))
|
74
|
+
@request.to_s.should include('foo: bar')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EM::Twitter::Response do
|
4
|
+
|
5
|
+
describe '.new' do
|
6
|
+
it 'initializes an empty body' do
|
7
|
+
EM::Twitter::Response.new.body.should eq('')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'initializes with a body parameter' do
|
11
|
+
EM::Twitter::Response.new('ohai').body.should eq('ohai')
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#concat' do
|
16
|
+
it 'sets the body when empty' do
|
17
|
+
response = EM::Twitter::Response.new
|
18
|
+
response.concat('{ "status" : true }')
|
19
|
+
response.body.should eq('{ "status" : true }')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'appends to an existing body' do
|
23
|
+
response = EM::Twitter::Response.new('{ "status" : true')
|
24
|
+
response.concat(', "enabled" : false }')
|
25
|
+
response.body.should eq('{ "status" : true, "enabled" : false }')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'only appends when passed json' do
|
29
|
+
str = '{ "status" : true'
|
30
|
+
response = EM::Twitter::Response.new(str)
|
31
|
+
response.concat('ohai')
|
32
|
+
response.body.should eq(str)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'passively fails on nil' do
|
36
|
+
response = EM::Twitter::Response.new
|
37
|
+
lambda {
|
38
|
+
response.concat(nil)
|
39
|
+
}.should_not raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'passively fails on empty strings' do
|
43
|
+
response = EM::Twitter::Response.new('ohai')
|
44
|
+
response.concat('')
|
45
|
+
response.body.should eq('ohai')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'passively fails on blank strings' do
|
49
|
+
response = EM::Twitter::Response.new('ohai')
|
50
|
+
response.concat(' ')
|
51
|
+
response.body.should eq('ohai')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'is aliased as <<' do
|
55
|
+
response = EM::Twitter::Response.new
|
56
|
+
response << '{ "status" : true }'
|
57
|
+
response.body.should eq('{ "status" : true }')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#complete?' do
|
62
|
+
it 'returns false when an incomplete body' do
|
63
|
+
EM::Twitter::Response.new('{ "status" : true').complete?.should be_false
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns false when an complete body' do
|
67
|
+
EM::Twitter::Response.new('{ "status" : true }').complete?.should be_true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#empty?' do
|
72
|
+
it 'returns true when an empty body' do
|
73
|
+
EM::Twitter::Response.new.should be_empty
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'returns false when a body is present' do
|
77
|
+
EM::Twitter::Response.new('{ "status" : true }').should_not be_empty
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#reset' do
|
82
|
+
it 'resets the body to an empty string' do
|
83
|
+
response = EM::Twitter::Response.new('{ "status" : true }')
|
84
|
+
response.body.length.should be > 0
|
85
|
+
response.reset
|
86
|
+
response.body.should eq('')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EM::Twitter do
|
4
|
+
|
5
|
+
describe '.logger' do
|
6
|
+
it 'returns a Logger by default' do
|
7
|
+
EM::Twitter.logger.should be_kind_of(Logger)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.logger=' do
|
12
|
+
it 'assigns a custom logger' do
|
13
|
+
FakeLogger = Class.new
|
14
|
+
EM::Twitter.logger = FakeLogger.new
|
15
|
+
EM::Twitter.logger.should be_kind_of(FakeLogger)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'simplecov'
|
3
|
+
|
4
|
+
require 'em-twitter'
|
5
|
+
require 'rspec'
|
6
|
+
require 'mockingbird'
|
7
|
+
|
8
|
+
def test_options
|
9
|
+
{ :host => '127.0.0.1', :port => 9551, :quiet => true }
|
10
|
+
end
|
11
|
+
|
12
|
+
def default_options
|
13
|
+
EM::Twitter::DEFAULT_CONNECTION_OPTIONS.merge({
|
14
|
+
:path => '/1/statuses/filter.json',
|
15
|
+
:params => {
|
16
|
+
:track => 'nfl'
|
17
|
+
},
|
18
|
+
:oauth => {
|
19
|
+
:consumer_key => 'cVcIw5zoLFE2a4BdDsmmA',
|
20
|
+
:consumer_secret => 'yYgVgvTT9uCFAi2IuscbYTCqwJZ1sdQxzISvLhNWUA',
|
21
|
+
:token => '4618-H3gU7mjDQ7MtFkAwHhCqD91Cp4RqDTp1AKwGzpHGL3I',
|
22
|
+
:token_secret => 'xmc9kFgOXpMdQ590Tho2gV7fE71v5OmBrX8qPGh7Y'
|
23
|
+
},
|
24
|
+
:ssl => false
|
25
|
+
}).merge(test_options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def proxy_options
|
29
|
+
{ :proxy => { :uri => 'http://my-proxy:8080', :user => 'username', :password => 'password'} }
|
30
|
+
end
|
31
|
+
|
32
|
+
def error_callback_invoked(callback, code, desc, msg = nil)
|
33
|
+
describe "##{callback}" do
|
34
|
+
before do
|
35
|
+
Mockingbird.setup(test_options) do
|
36
|
+
status code, desc
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
after { Mockingbird.teardown }
|
41
|
+
|
42
|
+
it "it invokes the callback on a #{code}" do
|
43
|
+
called = false
|
44
|
+
response_code = nil
|
45
|
+
|
46
|
+
if msg
|
47
|
+
block = lambda do |code|
|
48
|
+
response_code = code
|
49
|
+
called = true
|
50
|
+
EM.stop
|
51
|
+
end
|
52
|
+
else
|
53
|
+
block = lambda do
|
54
|
+
called = true
|
55
|
+
EM.stop
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
EM.run do
|
60
|
+
client = EM::Twitter::Client.connect(default_options)
|
61
|
+
client.send(:"#{callback}", &block)
|
62
|
+
end
|
63
|
+
|
64
|
+
response_code.should eq("Unhandled status code: #{code}.") if response_code
|
65
|
+
called.should be_true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|