tkellem 0.9.0.beta3 → 0.9.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ require 'spec_helper'
2
+ require 'tkellem/irc_server'
3
+
4
+ include Tkellem
5
+
6
+ describe Bouncer, "connection" do
7
+ before do
8
+ EM.stub!(:add_timer).and_return(nil)
9
+ end
10
+
11
+ def make_server
12
+ network = Network.create!(:hosts => [Host.create!(:address => 'localhost', :port => 4321)], :name => 'test')
13
+ b = Bouncer.new(NetworkUser.create!(:user => User.new(:username => 'speccer'), :network => network))
14
+ b
15
+ end
16
+
17
+ def send_welcome(s, &just_before_last)
18
+ s.should_receive(:send_msg).with("USER speccer somehost tkellem :speccer@tkellem")
19
+ s.should_receive(:send_msg).with("NICK speccer")
20
+ s.should_receive(:send_msg).with("AWAY :Away")
21
+ s.connection_established(nil)
22
+ s.server_msg(IrcMessage.parse("001 blah blah"))
23
+ s.server_msg(IrcMessage.parse("002 more blah"))
24
+ s.server_msg(IrcMessage.parse("003 even more blah"))
25
+ just_before_last && just_before_last.call
26
+ s.server_msg(IrcMessage.parse("376 :end of MOTD"))
27
+ end
28
+
29
+ def connected_server
30
+ s = make_server
31
+ send_welcome(s)
32
+ s.connected?.should be_true
33
+ s
34
+ end
35
+
36
+ it "should connect to the server on creation" do
37
+ s = make_server
38
+ s.connected?.should_not be_true
39
+ s.should_receive(:send_msg).with("USER speccer somehost tkellem :speccer@tkellem")
40
+ s.should_receive(:send_msg).with("NICK speccer")
41
+ s.connection_established(nil)
42
+ end
43
+
44
+ it "should pong" do
45
+ s = connected_server
46
+ s.should_receive(:send_msg).with("PONG tkellem!tkellem :HAI")
47
+ s.server_msg(IrcMessage.parse(":speccer!test@host ping :HAI"))
48
+ end
49
+
50
+ it "should ignore blank lines" do
51
+ b = mock("bouncer", :trace => nil)
52
+ b.should_receive(:failsafe).and_yield
53
+ s = em(IrcServerConnection).new('connected', b, false)
54
+ b.should_receive(:server_msg).never
55
+ s.receive_line("")
56
+ end
57
+
58
+ def tk_server
59
+ $tk_server ||= TkellemServer.new
60
+ end
61
+
62
+ after(:each) do
63
+ $tk_server.stop if $tk_server
64
+ $tk_server = nil
65
+ end
66
+
67
+ def network_user(opts = {})
68
+ opts[:user] ||= @user ||= User.create!(:username => 'speccer', :password => 'test123')
69
+ opts[:network] ||= @network ||= Network.create!(:name => 'localhost')
70
+ @network_user ||= NetworkUser.create!(opts)
71
+ end
72
+
73
+ def bouncer(opts = {})
74
+ tk_server
75
+ network_user
76
+ @bouncer = $tk_server.bouncers.values.last
77
+ if opts[:connect]
78
+ @server_conn = em(IrcServerConnection).new(nil, @bouncer, false)
79
+ @server_conn.stub!(:send_data)
80
+ @bouncer.connection_established(@server_conn)
81
+ @bouncer.send :ready!
82
+ end
83
+ @bouncer
84
+ end
85
+
86
+ def client_connection(opts = {})
87
+ @client ||= em(BouncerConnection).new(tk_server, false)
88
+ if opts[:connect]
89
+ end
90
+ @client
91
+ end
92
+
93
+ it "should force the client nick on connect" do
94
+ network_user(:nick => 'mynick')
95
+ bouncer(:connect => true)
96
+ @bouncer.server_msg(m ":mynick JOIN #t1")
97
+ client_connection
98
+ @client.should_receive(:send_msg).with(":some_other_nick NICK mynick")
99
+ @client.should_receive(:send_msg).with(":mynick JOIN #t1")
100
+ @client.receive_line("PASS test123")
101
+ @client.receive_line("NICK some_other_nick")
102
+ @client.receive_line("USER #{@user.username}@#{@network.name} a b :c")
103
+ end
104
+
105
+ it "should attempt another nick if the default is taken" do
106
+ network_user(:nick => 'mynick')
107
+ bouncer
108
+ @server_conn = em(IrcServerConnection).new(nil, @bouncer, false)
109
+ @server_conn.stub!(:send_data)
110
+ @bouncer.connection_established(@server_conn)
111
+ @server_conn.should_receive(:send_data).with("NICK mynick_\r\n")
112
+ @bouncer.server_msg(m ":server 433 * mynick :Nickname already in use")
113
+ @bouncer.nick.should == 'mynick_'
114
+ @bouncer.send :ready!
115
+ end
116
+
117
+ it "should change nicks if a client sends nick after connecting" do
118
+ network_user(:nick => 'mynick')
119
+ bouncer(:connect => true)
120
+ @bouncer.server_msg(m ":mynick JOIN #t1")
121
+ client_connection
122
+ @client.should_receive(:send_msg).with(":mynick JOIN #t1")
123
+ @client.receive_line("PASS test123")
124
+ @client.receive_line("NICK mynick")
125
+ @client.receive_line("USER #{@user.username}@#{@network.name} a b :c")
126
+ @bouncer.nick.should == 'mynick'
127
+ @bouncer.client_msg(@client, m("NICK some_other"))
128
+ @bouncer.nick.should == 'some_other'
129
+ end
130
+
131
+ it "should change nicks if a server forces nick change" do
132
+ network_user(:nick => 'mynick')
133
+ bouncer(:connect => true)
134
+ @bouncer.server_msg(m ":mynick JOIN #t1")
135
+ client_connection
136
+ @client.should_receive(:send_msg).with(":mynick JOIN #t1")
137
+ @client.receive_line("PASS test123")
138
+ @client.receive_line("NICK mynick")
139
+ @client.receive_line("USER #{@user.username}@#{@network.name} a b :c")
140
+ @bouncer.nick.should == 'mynick'
141
+ @client.should_receive(:send_msg).with(m ":mynick NICK some_other")
142
+ @bouncer.server_msg(m ":mynick NICK some_other")
143
+ @bouncer.nick.should == 'some_other'
144
+ end
145
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,17 +5,30 @@ require 'tkellem'
5
5
  require 'rspec'
6
6
 
7
7
  Tkellem::EasyLogger.logger = Logger.new("test.log")
8
+ ActiveRecord::Base.logger = Tkellem::EasyLogger.logger
8
9
 
9
- TestDB = Tkellem::TkellemServer.initialize_database(':memory:')
10
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
11
+ ActiveRecord::Migration.verbose = false
12
+ ActiveRecord::Migrator.migrate(File.expand_path("../../lib/tkellem/migrations", __FILE__), nil)
10
13
 
11
14
  RSpec.configure do |config|
12
- config.around(:each) do |block|
13
- TestDB.transaction(:rollback => :always) do
14
- block.run()
15
+ config.around(:each) do |test|
16
+ EM.run do
17
+ ActiveRecord::Base.transaction do
18
+ test.run
19
+ raise ActiveRecord::Rollback
20
+ end
21
+ EM.stop
15
22
  end
16
23
  end
17
24
 
18
25
  def m(line)
19
26
  IrcMessage.parse(line)
20
27
  end
28
+
29
+ def em(mod)
30
+ c = Class.new
31
+ c.send(:include, mod)
32
+ c
33
+ end
21
34
  end
data/tkellem.gemspec CHANGED
@@ -17,12 +17,11 @@ Gem::Specification.new do |s|
17
17
  s.default_executable = %q{tkellem}
18
18
  s.require_paths = ["lib"]
19
19
 
20
- s.add_dependency "celluloid", "~> 0.14.1"
21
- s.add_dependency "celluloid-io", "~> 0.14.1"
22
- s.add_dependency "activesupport", "3.2.10"
23
- s.add_dependency "sequel", "3.42.0"
24
- s.add_dependency "sqlite3", "1.3.6"
20
+ s.add_dependency "eventmachine", "~> 1.0.3"
21
+ s.add_dependency "activerecord", "~> 4.0.0.rc2"
22
+ s.add_dependency "sqlite3", "~> 1.3.3"
23
+ s.add_dependency "rails-observers"
25
24
 
26
- s.add_development_dependency "rake"
27
25
  s.add_development_dependency "rspec", "~> 2.5"
26
+ s.add_development_dependency "simplecov"
28
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tkellem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0.beta3
4
+ version: 0.9.0.beta4
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -9,16 +9,16 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-20 00:00:00.000000000 Z
12
+ date: 2013-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: celluloid
15
+ name: eventmachine
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.14.1
21
+ version: 1.0.3
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,15 +26,15 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 0.14.1
29
+ version: 1.0.3
30
30
  - !ruby/object:Gem::Dependency
31
- name: celluloid-io
31
+ name: activerecord
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 0.14.1
37
+ version: 4.0.0.rc2
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,57 +42,57 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 0.14.1
45
+ version: 4.0.0.rc2
46
46
  - !ruby/object:Gem::Dependency
47
- name: activesupport
47
+ name: sqlite3
48
48
  requirement: !ruby/object:Gem::Requirement
49
49
  none: false
50
50
  requirements:
51
- - - '='
51
+ - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 3.2.10
53
+ version: 1.3.3
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  none: false
58
58
  requirements:
59
- - - '='
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 3.2.10
61
+ version: 1.3.3
62
62
  - !ruby/object:Gem::Dependency
63
- name: sequel
63
+ name: rails-observers
64
64
  requirement: !ruby/object:Gem::Requirement
65
65
  none: false
66
66
  requirements:
67
- - - '='
67
+ - - ! '>='
68
68
  - !ruby/object:Gem::Version
69
- version: 3.42.0
69
+ version: '0'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
- - - '='
75
+ - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
- version: 3.42.0
77
+ version: '0'
78
78
  - !ruby/object:Gem::Dependency
79
- name: sqlite3
79
+ name: rspec
80
80
  requirement: !ruby/object:Gem::Requirement
81
81
  none: false
82
82
  requirements:
83
- - - '='
83
+ - - ~>
84
84
  - !ruby/object:Gem::Version
85
- version: 1.3.6
86
- type: :runtime
85
+ version: '2.5'
86
+ type: :development
87
87
  prerelease: false
88
88
  version_requirements: !ruby/object:Gem::Requirement
89
89
  none: false
90
90
  requirements:
91
- - - '='
91
+ - - ~>
92
92
  - !ruby/object:Gem::Version
93
- version: 1.3.6
93
+ version: '2.5'
94
94
  - !ruby/object:Gem::Dependency
95
- name: rake
95
+ name: simplecov
96
96
  requirement: !ruby/object:Gem::Requirement
97
97
  none: false
98
98
  requirements:
@@ -107,22 +107,6 @@ dependencies:
107
107
  - - ! '>='
108
108
  - !ruby/object:Gem::Version
109
109
  version: '0'
110
- - !ruby/object:Gem::Dependency
111
- name: rspec
112
- requirement: !ruby/object:Gem::Requirement
113
- none: false
114
- requirements:
115
- - - ~>
116
- - !ruby/object:Gem::Version
117
- version: '2.5'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ~>
124
- - !ruby/object:Gem::Version
125
- version: '2.5'
126
110
  description:
127
111
  email:
128
112
  - brian@codekitchen.net
@@ -152,9 +136,9 @@ files:
152
136
  - lib/tkellem.rb
153
137
  - lib/tkellem/bouncer.rb
154
138
  - lib/tkellem/bouncer_connection.rb
155
- - lib/tkellem/celluloid_tools.rb
156
139
  - lib/tkellem/daemon.rb
157
140
  - lib/tkellem/irc_message.rb
141
+ - lib/tkellem/irc_server.rb
158
142
  - lib/tkellem/migrations/001_init_db.rb
159
143
  - lib/tkellem/migrations/002_at_connect_columns.rb
160
144
  - lib/tkellem/migrations/003_settings.rb
@@ -173,7 +157,9 @@ files:
173
157
  - lib/tkellem/version.rb
174
158
  - resources/bot_command_descriptions.yml
175
159
  - resources/setting_descriptions.yml
160
+ - spec/bouncer_connection_spec.rb
176
161
  - spec/irc_message_spec.rb
162
+ - spec/irc_server_spec.rb
177
163
  - spec/spec_helper.rb
178
164
  - tkellem.gemspec
179
165
  homepage: http://github.com/codekitchen/tkellem
@@ -190,7 +176,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
190
176
  version: '0'
191
177
  segments:
192
178
  - 0
193
- hash: -3396799621810134094
179
+ hash: -629410189197339585
194
180
  required_rubygems_version: !ruby/object:Gem::Requirement
195
181
  none: false
196
182
  requirements:
@@ -204,5 +190,7 @@ signing_key:
204
190
  specification_version: 3
205
191
  summary: IRC bouncer with multi-client support
206
192
  test_files:
193
+ - spec/bouncer_connection_spec.rb
207
194
  - spec/irc_message_spec.rb
195
+ - spec/irc_server_spec.rb
208
196
  - spec/spec_helper.rb
@@ -1,131 +0,0 @@
1
- require 'openssl'
2
- require 'celluloid/io'
3
-
4
- module Tkellem
5
- module CelluloidTools
6
-
7
- # Generates a new SSL context with a new cert and key
8
- # Great for easily getting up and running, but not necessarily a good idea for
9
- # production use
10
- def self.generate_ssl_ctx
11
- key = OpenSSL::PKey::RSA.new(2048)
12
-
13
- dn = OpenSSL::X509::Name.parse("/CN=tkellem-auto")
14
- cert = OpenSSL::X509::Certificate.new
15
- cert.version = 2
16
- cert.serial = 1
17
- cert.subject = dn
18
- cert.issuer = dn
19
- cert.public_key = key.public_key
20
- cert.not_before = Time.now
21
- cert.not_after = Time.now + 94670777 # 3 years
22
- cert.sign(key, OpenSSL::Digest::SHA1.new)
23
-
24
- ctx = OpenSSL::SSL::SSLContext.new
25
- ctx.key = key
26
- ctx.cert = cert
27
-
28
- ctx
29
- end
30
-
31
- class BackoffSupervisor < ::Celluloid::SupervisionGroup
32
- attr_reader :registry
33
-
34
- def restart_actor(actor, reason)
35
- member = @members.find do |member|
36
- member.actor == actor
37
- end
38
- raise "a group member went missing. This shouldn't be!" unless member
39
-
40
- if reason
41
- end
42
-
43
- member.restart(reason)
44
- end
45
- end
46
-
47
- class Listener < Struct.new(:server, :callback)
48
- include Celluloid::IO
49
-
50
- def self.start(*args, &callback)
51
- listener = self.new(*args)
52
- listener.callback = callback
53
- listener.async.run
54
- listener
55
- end
56
-
57
- def run
58
- loop { handle_connection(server.accept) }
59
- end
60
-
61
- def handle_connection(socket)
62
- callback.(socket)
63
- end
64
-
65
- finalizer :close
66
-
67
- def close
68
- server.try(:close) unless server.try(:closed?)
69
- end
70
- end
71
-
72
- class TCPListener < Listener
73
- def initialize(host, port)
74
- self.server = TCPServer.new(host, port)
75
- end
76
- end
77
-
78
- class SSLListener < Listener
79
- def initialize(host, port)
80
- self.server = SSLServer.new(TCPServer.new(host, port), CelluloidTools.generate_ssl_ctx)
81
- end
82
- end
83
-
84
- class UnixListener < Listener
85
- def initialize(socket_path)
86
- self.server = UNIXServer.new(socket_path)
87
- end
88
- end
89
-
90
- module LineReader
91
- def self.included(k)
92
- k.send :finalizer, :close_connection
93
- end
94
-
95
- def readline
96
- @delimiter ||= "\r\n"
97
- @readline_buffer ||= ''
98
- loop do
99
- if idx = @readline_buffer.index(@delimiter)
100
- postidx = idx + @delimiter.size
101
- line = @readline_buffer[0, postidx]
102
- @readline_buffer = @readline_buffer[postidx..-1]
103
- return line
104
- else
105
- @socket.readpartial(4096, @readline_buffer)
106
- end
107
- end
108
- end
109
-
110
- def close_connection
111
- @socket.close if @socket && !@socket.closed?
112
- end
113
-
114
- def run
115
- loop do
116
- line = readline.force_encoding(Encoding::UTF_8)
117
- receive_line(line)
118
- end
119
- rescue EOFError, IOError, OpenSSL::SSL::SSLError
120
- unbind
121
- end
122
-
123
- def receive_line(line)
124
- end
125
-
126
- def unbind
127
- end
128
- end
129
-
130
- end
131
- end