akane 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,51 @@
1
+ require 'akane/storages/abstract_storage'
2
+
3
+ module Akane
4
+ module Storages
5
+ class Mock < AbstractStorage
6
+ class << self
7
+ def recorded_tweets
8
+ @recorded_tweets ||= []
9
+ end
10
+
11
+ def deletion_marks
12
+ @deletion_marks ||= []
13
+ end
14
+
15
+ def recorded_events
16
+ @recorded_events ||= []
17
+ end
18
+
19
+ def recorded_messages
20
+ @recorded_messages ||= []
21
+ end
22
+
23
+ def reset!
24
+ [recorded_tweets, deletion_marks,
25
+ recorded_events, recorded_messages].each(&:clear)
26
+ self
27
+ end
28
+ end
29
+
30
+ def record_tweet(account, tweet)
31
+ self.class.recorded_tweets << [account, tweet]
32
+ self
33
+ end
34
+
35
+ def mark_as_deleted(account, user_id, tweet_id)
36
+ self.class.deletion_marks << [account, user_id, tweet_id]
37
+ self
38
+ end
39
+
40
+ def record_event(account, event)
41
+ self.class.recorded_events << [account, event]
42
+ self
43
+ end
44
+
45
+ def record_message(account, message)
46
+ self.class.recorded_messages << [account, message]
47
+ self
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ require 'akane/storages/abstract_storage'
2
+
3
+ module Akane
4
+ module Storages
5
+ class Stdout < AbstractStorage
6
+ def record_tweet(account, tweet)
7
+ $stdout.puts "[#{account}] #{tweet["user"]["screen_name"]}: #{tweet["text"]}"
8
+ end
9
+
10
+ def mark_as_deleted(account, user_id, tweet_id)
11
+ $stdout.puts "[#{account}](DELETION) #{user_id}/#{tweet_id}"
12
+ end
13
+
14
+ def record_event(account, event)
15
+ $stdout.puts "[#{account}](EVENT) #{event["event"]}: #{event["source"]["screen_name"]}-> #{event["target"]["screen_name"]}"
16
+ end
17
+
18
+ def record_message(account, message)
19
+ $stdout.puts "[#{account}](DM) #{message["user"]["screen_name"]}: #{message["text"]}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module Akane
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'logger'
3
+ require 'akane/config'
4
+
5
+ describe Akane::Config do
6
+ subject { described_class.new("log" => File::NULL, "foo" => "bar") }
7
+
8
+ describe "#logger" do
9
+ it "returns logger" do
10
+ expect(subject.logger).to be_a_kind_of(Logger)
11
+ end
12
+ end
13
+
14
+ describe "#[]" do
15
+ it "returns from config hash" do
16
+ expect(subject["foo"]).to eq "bar"
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+ require 'eventmachine'
3
+ require 'akane/manager'
4
+ require 'akane/receivers/stream'
5
+ require 'akane/storages/mock'
6
+ require 'akane/config'
7
+
8
+ describe Akane::Manager do
9
+ let(:conf_accounts) do
10
+ {
11
+ "a" => {"token" => "a-access-token", "secret" => "a-access-secret"},
12
+ }
13
+ end
14
+ let(:conf_storages) do
15
+ [
16
+ { "mock" => {"a" => "b"} }
17
+ ]
18
+ end
19
+
20
+ let(:config) do
21
+ Akane::Config.new(
22
+ "consumer" => {
23
+ "token" => "consumer-token", "secret" => "consumer-secret"
24
+ },
25
+ "accounts" => conf_accounts,
26
+ "storages" => conf_storages
27
+ ).tap { |_| _.stub(logger: Logger.new(nil)) }
28
+ end
29
+
30
+ subject { Akane::Manager.new(config) }
31
+
32
+ before do
33
+ EM.stub(:run) { |&block| block.call }
34
+ end
35
+
36
+ # receivers -> manager -> recorder -> storage
37
+
38
+ describe "#prepare" do
39
+ it "creates receivers" do
40
+ Akane::Receivers::Stream.should_receive(:new) \
41
+ .with(consumer: {token: 'consumer-token', secret: 'consumer-secret'},
42
+ account: {token: 'a-access-token', secret: 'a-access-secret'},
43
+ logger: config.logger) \
44
+ .and_return(double("a").as_null_object)
45
+
46
+ subject.prepare
47
+ end
48
+
49
+ it "instantiates storages" do
50
+ Akane::Storages::Mock.should_receive(:new).with(config: {"a" => "b"}, logger: config.logger)
51
+ subject.prepare
52
+ end
53
+
54
+ it "creates recorder with storages" do
55
+ storage = double("storage")
56
+ Akane::Storages::Mock.stub(new: storage)
57
+ Akane::Recorder.should_receive(:new).with([storage], logger: config.logger).and_call_original
58
+
59
+ subject.prepare
60
+ end
61
+ end
62
+
63
+ describe "#start" do
64
+ let(:receiver) { double("a").as_null_object }
65
+ let(:recorder) { double("recorder").as_null_object }
66
+ before do
67
+ Akane::Receivers::Stream.stub(new: receiver)
68
+ Akane::Recorder.stub(new: recorder)
69
+
70
+ @on_event, @on_tweet, @on_delete, @on_message = nil
71
+ receiver.stub(:on_event) { |&block| @on_event = block }
72
+ receiver.stub(:on_tweet) { |&block| @on_tweet = block }
73
+ receiver.stub(:on_delete) { |&block| @on_delete = block }
74
+ receiver.stub(:on_message) { |&block| @on_message = block }
75
+
76
+ subject.prepare
77
+ end
78
+
79
+ it "starts all receivers" do
80
+ receiver.should_receive(:start)
81
+ subject.start
82
+ end
83
+
84
+ it "starts all receivers" do
85
+ recorder.should_receive(:run)
86
+ subject.start
87
+ end
88
+
89
+ it "sends all to recorder" do
90
+ subject.start
91
+
92
+ recorder.should_receive(:record_tweet).with('a', "id" => 42)
93
+ recorder.should_receive(:record_event).with('a', "event" => 'favorite')
94
+ recorder.should_receive(:mark_as_deleted).with('a', 5, 420)
95
+ recorder.should_receive(:record_message).with('a', 'mes' => 'sage')
96
+
97
+ @on_tweet.call("id" => 42)
98
+ @on_event.call("event" => 'favorite')
99
+ @on_delete.call(5, 420)
100
+ @on_message.call('mes' => 'sage')
101
+ end
102
+ end
103
+
104
+ describe "#run" do
105
+ it "calls setup then start"
106
+ end
107
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+ require 'akane/receivers/abstract_receiver'
3
+
4
+ describe Akane::Receivers::AbstractReceiver do
5
+ =begin
6
+ subject { described_class.new(consumer: {token: 'consumer-token', secret: 'consumer-secret'}, account: {token: '42-access-token', secret: 'access-secret'}) }
7
+ describe "#start" do
8
+ it "starts listening" do
9
+ subject.start
10
+ end
11
+
12
+ it "starts returning running? true" do
13
+ expect { subject.start } \
14
+ .to change { subject.running? } \
15
+ .from(false).to(true)
16
+ end
17
+ end
18
+
19
+ describe "#stop" do
20
+ it "stops listening" do
21
+ subject.stop
22
+ end
23
+
24
+ it "stops returning running? true" do
25
+ subject.start
26
+
27
+ expect { subject.stop } \
28
+ .to change { subject.running? } \
29
+ .from(true).to(false)
30
+ end
31
+ end
32
+
33
+ describe "when received tweet" do
34
+ it "calls on_tweet hook" do
35
+ end
36
+ end
37
+
38
+ describe "when received event" do
39
+ it "calls on_event hook" do
40
+ end
41
+ end
42
+
43
+ describe "when error occured" do
44
+ it "calls on_error hook" do
45
+ end
46
+ end
47
+ =end
48
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+ require 'logger'
3
+ require 'akane/receivers/stream'
4
+
5
+ describe Akane::Receivers::Stream do
6
+ let(:config) { {} }
7
+ subject { described_class.new(consumer: {token: 'consumer-token', secret: 'consumer-secret'}, account: {token: '42-access-token', secret: 'access-secret'}, config: config, logger: Logger.new(nil)) }
8
+
9
+ after(:each) do
10
+ TweetStream::MockClient.clients.clear
11
+ end
12
+
13
+ describe "#start" do
14
+ it "starts listening" do
15
+ expect { subject.start } \
16
+ .to change { TweetStream::MockClient.clients.size } \
17
+ .by(1)
18
+ end
19
+
20
+ it "starts returning running? true" do
21
+ expect { subject.start } \
22
+ .to change { subject.running? } \
23
+ .from(false).to(true)
24
+ end
25
+ end
26
+
27
+ describe "#stop" do
28
+ before do
29
+ subject.start
30
+ end
31
+
32
+ it "stops listening" do
33
+ expect { subject.stop } \
34
+ .to change { TweetStream::MockClient.clients.size } \
35
+ .by(-1)
36
+ end
37
+
38
+ it "stops returning running? true" do
39
+ expect { subject.stop } \
40
+ .to change { subject.running? } \
41
+ .from(true).to(false)
42
+ end
43
+ end
44
+
45
+ describe "when received tweet" do
46
+ before do
47
+ subject.start
48
+ end
49
+
50
+ it "calls on_tweet hook" do
51
+ called = nil
52
+ subject.on_tweet do |tweet|
53
+ called = tweet
54
+ end
55
+ TweetStream::MockClient.invoke('timeline_status', foo: :bar)
56
+ expect(called).to eq(foo: :bar)
57
+ end
58
+ end
59
+
60
+ describe "when received message" do
61
+ before do
62
+ subject.start
63
+ end
64
+
65
+ it "calls on_message hook" do
66
+ called = nil
67
+ subject.on_message do |message|
68
+ called = message
69
+ end
70
+ TweetStream::MockClient.invoke('direct_message', foo: :bar)
71
+ expect(called).to eq(foo: :bar)
72
+ end
73
+ end
74
+
75
+ describe "when received deletion" do
76
+ before do
77
+ subject.start
78
+ end
79
+
80
+ it "calls on_delete hook" do
81
+ called = nil
82
+ subject.on_delete do |u,t|
83
+ called = [u,t]
84
+ end
85
+ TweetStream::MockClient.invoke('delete', 424242, 42)
86
+ expect(called).to eq([42,424242])
87
+ end
88
+ end
89
+
90
+ describe "when received event" do
91
+ before do
92
+ subject.start
93
+ end
94
+
95
+ it "calls on_event hook" do
96
+ called = nil
97
+ subject.on_event do |h|
98
+ called = h
99
+ end
100
+ TweetStream::MockClient.invoke('anything', "event" => "favorite")
101
+ TweetStream::MockClient.invoke('anything', "something" => "else")
102
+ expect(called).to eq("event" => "favorite")
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+ require 'akane/recorder'
3
+
4
+ describe Akane::Recorder do
5
+ let(:storages) do
6
+ [
7
+ double("storage0")
8
+ ]
9
+ end
10
+ subject { described_class.new(storages) }
11
+
12
+ describe "recording tweets" do
13
+ it "records tweet" do
14
+ storages[0].should_receive(:record_tweet).with('a', {"id" => 42})
15
+ subject.record_tweet('a', "id" => 42)
16
+ subject.dequeue(true)
17
+ end
18
+
19
+ it "doesn't record tweets which already recorded recently" do
20
+ storages[0].should_receive(:record_tweet).with('a', {"id" => 40})
21
+ storages[0].should_receive(:record_tweet).with('a', {"id" => 42})
22
+
23
+ subject.record_tweet('a', "id" => 40)
24
+ subject.record_tweet('a', "id" => 42)
25
+ subject.dequeue(true)
26
+ subject.dequeue(true)
27
+ subject.record_tweet('a', "id" => 42)
28
+ subject.dequeue(true)
29
+ end
30
+
31
+ it "records retweeted tweet" do
32
+ tweet = {"id" => 42, "text" => "foo", "user" => {"id" => 1, "screen_name" => "a"}}
33
+ retweet = {"id" => 43, "text" => "RT @a: foo", "user" => {"id" => 2, "screen_name" => "b"}, "retweeted_status" => tweet}
34
+ storages[0].should_receive(:record_tweet).with('a', retweet)
35
+ storages[0].should_receive(:record_tweet).with('a', tweet)
36
+ subject.record_tweet('a', retweet)
37
+ subject.dequeue(true)
38
+ end
39
+ end
40
+
41
+ describe "marking deletion" do
42
+ it "marks as deleted" do
43
+ subject.mark_as_deleted('foo', 1, 42)
44
+
45
+ storages[0].should_receive(:mark_as_deleted).with('foo', 1, 42)
46
+ subject.dequeue(true)
47
+ end
48
+ end
49
+
50
+ describe "recording messages" do
51
+ it "records message" do
52
+ subject.record_message('foo', {"id" => 42})
53
+
54
+ storages[0].should_receive(:record_message).with('foo', "id" => 42)
55
+ subject.dequeue(true)
56
+ end
57
+ end
58
+
59
+ describe "recording event" do
60
+ it "records event" do
61
+ subject.record_event('foo', {"event" => "favorite"})
62
+
63
+ storages[0].should_receive(:record_event).with('foo', "event" => "favorite")
64
+ subject.dequeue(true)
65
+ end
66
+ end
67
+
68
+ describe "#run" do
69
+ before do
70
+ @th = Thread.new { subject.run(true) }
71
+ @th.abort_on_exception = true
72
+ end
73
+
74
+ it "continues dequeuing the queue" do
75
+ storages[0].should_receive(:record_tweet).with('a', {"id" => 42})
76
+ storages[0].should_receive(:record_tweet).with('b', {"id" => 43})
77
+ subject.record_tweet('a', "id" => 42)
78
+ subject.record_tweet('b', "id" => 43)
79
+ 10.times { break if subject.queue_length.zero?; sleep 0.1 }
80
+ end
81
+
82
+ after do
83
+ @th.kill if @th && @th.alive?
84
+ end
85
+ end
86
+ end