tkellem 0.9.0.beta3 → 0.9.0.beta4

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.
@@ -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