zerg_support 0.0.9 → 0.1

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/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ v0.1. Socket primitives.
2
+
1
3
  v0.0.9. Changed ProcTable wrapper to deal with API change in 0.8.0.
2
4
 
3
5
  v0.0.8. Extension emulation works in Windows without a build environment.
data/Manifest CHANGED
@@ -1,10 +1,14 @@
1
1
  CHANGELOG
2
2
  lib/zerg_support/event_machine/connection_mocks.rb
3
- lib/zerg_support/event_machine/frame_protocol.rb
4
- lib/zerg_support/event_machine/object_protocol.rb
3
+ lib/zerg_support/event_machine/protocol_adapter.rb
5
4
  lib/zerg_support/gems.rb
6
5
  lib/zerg_support/open_ssh.rb
7
6
  lib/zerg_support/process.rb
7
+ lib/zerg_support/protocols/frame_protocol.rb
8
+ lib/zerg_support/protocols/object_protocol.rb
9
+ lib/zerg_support/socket_factory.rb
10
+ lib/zerg_support/sockets/protocol_adapter.rb
11
+ lib/zerg_support/sockets/socket_mocks.rb
8
12
  lib/zerg_support/spawn.rb
9
13
  lib/zerg_support.rb
10
14
  LICENSE
@@ -19,4 +23,5 @@ test/test_gems.rb
19
23
  test/test_object_protocol.rb
20
24
  test/test_open_ssh.rb
21
25
  test/test_process.rb
26
+ test/test_socket_factory.rb
22
27
  test/test_spawn.rb
@@ -1,6 +1,9 @@
1
+ # :nodoc: namespace
2
+ module Zerg::Support::EventMachine
3
+
1
4
  # Mocks the sending end of an EventMachine connection.
2
5
  # The sent data is concatenated in a string available by calling #string.
3
- class Zerg::Support::EventMachine::SendMock
6
+ class SendMock
4
7
  attr_reader :string
5
8
 
6
9
  def initialize
@@ -10,17 +13,17 @@ class Zerg::Support::EventMachine::SendMock
10
13
  def send_data(data)
11
14
  @string << data
12
15
  end
13
- end
16
+ end # class SendMock
14
17
 
15
18
  # Mocks the receiving end of an EventMachine connection.
16
19
  # The data to be received is passed as an array of strings to the constructor.
17
20
  # Calling #replay mocks receiving the data.
18
- class Zerg::Support::EventMachine::ReceiveMock
21
+ class ReceiveMock
19
22
  attr_accessor :strings
20
23
  attr_accessor :objects
21
24
 
22
25
  def initialize(strings = [''])
23
- @strings = strings
26
+ @strings = strings.kind_of?(String) ? [strings] : strings
24
27
  @objects = []
25
28
  end
26
29
 
@@ -30,17 +33,14 @@ class Zerg::Support::EventMachine::ReceiveMock
30
33
  self
31
34
  end
32
35
 
33
- #:nodoc:
34
- def receive__object(object)
35
- @objects << object
36
- end
37
-
38
36
  # Declares the name of the object to be received. For instance, a frame
39
37
  # protocol would use :frame for name. This generates a receive_frame method,
40
38
  # and a frames accessor.
41
39
  def self.object_name(name)
42
- alias_method "receive_#{name}".to_sym, :receive__object
40
+ define_method(:"receive_#{name}") { |object| @objects << object }
43
41
  return if name == :object
44
- alias_method "#{name}s".to_sym, :objects
42
+ alias_method :"#{name}s", :objects
45
43
  end
46
- end
44
+ end # class ReceiveMock
45
+
46
+ end # namespace Zerg::Support::EventMachine
@@ -0,0 +1,53 @@
1
+ # :nodoc: namespace
2
+ module Zerg::Support::EventMachine
3
+
4
+ # Adapts generic Protocol modules for easy inclusion in EventMachine connection
5
+ # classes / modules.
6
+ module ProtocolAdapter
7
+ def self.adapter_module(protocol_module, object_name = nil)
8
+ unless object_name
9
+ object_name = /(^|:)([^:]*)Protocol$/.
10
+ match(protocol_module.name)[2].split(/(?=[A-Z])/).join('_').downcase
11
+ end
12
+
13
+ state_class = Class.new StateBase
14
+ state_class.send :include, protocol_module
15
+ state_class.class_eval do
16
+ # Called by the protocol when an entire object is available.
17
+ define_method :"received_#{object_name}" do |object|
18
+ @target.send :"receive_#{object_name}", object
19
+ end
20
+ end
21
+
22
+ adapter = Module.new
23
+ adapter.module_eval do
24
+ # Called by Event Machine when TCP stream data is available.
25
+ define_method :receive_data do |data|
26
+ @zerg_protocol_adapter_state ||= state_class.new self
27
+ @zerg_protocol_adapter_state.received_bytes data
28
+ end
29
+
30
+ # Called by the Event Machine user to send data.
31
+ define_method :"send_#{object_name}" do |object|
32
+ @zerg_protocol_adapter_state ||= state_class.new self
33
+ @zerg_protocol_adapter_state.send :"send_#{object_name}", object
34
+ end
35
+ end
36
+
37
+ adapter
38
+ end
39
+
40
+ # Base class for the adapter state.
41
+ class StateBase
42
+ def initialize(target)
43
+ @target = target
44
+ end
45
+
46
+ # Called by the protocol when an entire object is available.
47
+ def send_bytes(data)
48
+ @target.send_data data
49
+ end
50
+ end
51
+ end
52
+
53
+ end # namespace Zerg::Support::EventMachine
@@ -127,11 +127,10 @@ module Zerg::Support::Process
127
127
  self.kill_primitive pid, false
128
128
  Thread.new(pid) do |victim_pid|
129
129
  Kernel.sleep 0.2
130
- self.kill_primitive pid, true
130
+ self.kill_primitive(pid, true) rescue nil
131
131
  end
132
132
  rescue
133
133
  # we probably don't have the right to kill the process
134
- print "#{$!.class.name}: #{$!}\n"
135
134
  end
136
135
  end
137
136
 
@@ -1,10 +1,10 @@
1
1
  #:nodoc: namespace
2
- module Zerg::Support::EventMachine
2
+ module Zerg::Support::Protocols
3
3
 
4
- # Event Machine protocol for sending and receiving discrete-sized frames
5
- module FrameProtocol
6
- #:nodoc: This is called by Event Machine when TCP stream data is available.
7
- def receive_data(data)
4
+ # Protocol for sending and receiving discrete-sized frames over TCP streams.
5
+ module FrameProtocol
6
+ # Called when data is available from the TCP stream.
7
+ def received_bytes(data)
8
8
  @frame_protocol_varsize ||= ''
9
9
 
10
10
  i = 0
@@ -22,7 +22,7 @@ module FrameProtocol
22
22
  return if @frame_protocol_buffer.nil?
23
23
  break if @frame_protocol_bytes_left > data.size - i
24
24
 
25
- receive_frame @frame_protocol_buffer + data[i, @frame_protocol_bytes_left]
25
+ received_frame @frame_protocol_buffer + data[i, @frame_protocol_bytes_left]
26
26
  @frame_protocol_varsize, @frame_protocol_buffer = '', nil
27
27
  i += @frame_protocol_bytes_left
28
28
  end
@@ -32,14 +32,19 @@ module FrameProtocol
32
32
  end
33
33
 
34
34
  # Override to process incoming frames.
35
- def receive_frame(frame_data); end
35
+ def received_frame(frame_data); end
36
36
 
37
- # Sends a frame via the underlying Event Machine TCP stream.
37
+ # Sends a frame via the underlying TCP stream.
38
38
  def send_frame(frame_data)
39
- encoded_length = FrameProtocol.encode_natural(frame_data.length)
40
- send_data encoded_length + frame_data
39
+ send_bytes FrameProtocol.encode_frame(frame_data)
41
40
  end
42
41
 
42
+ # :nodoc: Encodes frame data into data to be sent across a TCP wire.
43
+ def self.encode_frame(frame_data)
44
+ encoded_length = FrameProtocol.encode_natural(frame_data.length)
45
+ encoded_length + frame_data
46
+ end
47
+
43
48
  #:nodoc: Encodes a natural (non-negative) integer into a string.
44
49
  def self.encode_natural(number)
45
50
  string = ''
@@ -65,4 +70,4 @@ module FrameProtocol
65
70
  end
66
71
  end
67
72
 
68
- end # namespace Zerg::Support::EventMachine
73
+ end # namespace Zerg::Support::Protocols
@@ -1,7 +1,7 @@
1
1
  require 'yaml'
2
2
 
3
3
  #:nodoc: namespace
4
- module Zerg::Support::EventMachine
4
+ module Zerg::Support::Protocols
5
5
 
6
6
  # Event Machine protocol for sending serializable objects.
7
7
  module ObjectProtocol
@@ -13,12 +13,12 @@ module ObjectProtocol
13
13
  end
14
14
 
15
15
  #:nodoc: Processes an incoming frame and de-serializes the object in it.
16
- def receive_frame(frame_data)
17
- receive_object YAML.load(frame_data)
16
+ def received_frame(frame_data)
17
+ received_object YAML.load(frame_data)
18
18
  end
19
19
 
20
20
  # Override to process incoming objects.
21
- def receive_object(object); end
21
+ def received_object(object); end
22
22
  end
23
23
 
24
- end # namespace Zerg::Support::EventMachine
24
+ end # namespace Zerg::Support::Protocols
@@ -0,0 +1,198 @@
1
+ require 'socket'
2
+
3
+ # :nodoc: namespace
4
+ module Zerg::Support
5
+
6
+ module SocketFactory
7
+ # Splits a host:port IP address into its components. IPv6 addresses welcome.
8
+ #
9
+ # The port will be nil if the IP address doesn't contain it.
10
+ def self.split_address(address)
11
+ port_match = /(^|[^:])\:([^:].*)$/.match(address)
12
+ if port_match
13
+ port = port_match[2]
14
+ host = address[0, address.length - port.length - 1]
15
+ [(host.empty? ? nil : host), port]
16
+ else
17
+ [address, nil]
18
+ end
19
+ end
20
+
21
+ # The host from a host:port IP address.
22
+ #
23
+ # Empty string if the IP address does not contain a host (e.g. :3000)
24
+ def self.host_from_address(address)
25
+ address and split_address(address)[0]
26
+ end
27
+
28
+ # The port from a host:port IP address.
29
+ #
30
+ # nil if the IP address does not contain a port (e.g. localhost)
31
+ def self.port_from_address(address)
32
+ address and (port_string = split_address(address)[1]) and port_string.to_i
33
+ end
34
+
35
+ # True for options requesting a connecting (as opposed to listening) socket.
36
+ def self.outbound?(options)
37
+ [:out_port, :out_host, :out_addr].any? { |k| options[k] }
38
+ end
39
+
40
+ # The host from a host:port IP address, in a form suitable for bind().
41
+ def self.bind_host(options)
42
+ host_from_address(options[:in_addr]) or options[:in_host] or '0.0.0.0'
43
+ end
44
+
45
+ # The port from a host:port IP address, in a form suitable for bind().
46
+ def self.bind_port(options)
47
+ port_from_address(options[:in_addr]) or options[:in_port] or 0
48
+ end
49
+
50
+ # An address suitable for bind() based on the options.
51
+ def self.bind_socket_address(options)
52
+ Socket::pack_sockaddr_in bind_port(options), bind_host(options)
53
+ end
54
+
55
+ # The host from a host:port IP address, in a form suitable for connect().
56
+ def self.connect_host(options)
57
+ options[:out_host] or host_from_address(options[:out_addr]) or 'localhost'
58
+ end
59
+
60
+ # The port from a host:port IP address, in a form suitable for connect().
61
+ def self.connect_port(options)
62
+ port_from_address(options[:out_addr]) or options[:out_port]
63
+ end
64
+
65
+ # True if the options indicate TCP should be used, false for UDP.
66
+ def self.tcp?(options)
67
+ options[:tcp] or !options[:udp]
68
+ end
69
+
70
+ # The socket() type based on the options.
71
+ def self.socket_type(options)
72
+ tcp?(options) ? Socket::SOCK_STREAM : Socket::SOCK_DGRAM
73
+ end
74
+
75
+ # Sets socket flags (via setsockopt) based on the options.
76
+ def self.set_options(socket, options)
77
+ if options[:no_delay]
78
+ if tcp?(options)
79
+ socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true
80
+ end
81
+ socket.sync = true
82
+ end
83
+
84
+ if options[:reuse_addr]
85
+ socket.setsockopt Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true
86
+ end
87
+
88
+ unless options[:reverse_lookup]
89
+ if socket.respond_to? :do_not_reverse_lookup
90
+ socket.do_not_reverse_lookup = true
91
+ else
92
+ # work around until the patch below actually gets committed:
93
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/2346
94
+ BasicSocket.do_not_reverse_lookup = true
95
+ end
96
+ end
97
+ end
98
+
99
+ # Hacks a socket's accept method so that new sockets have the given flags set.
100
+ #
101
+ # The flags are set in a similar manner to set_options.
102
+ def self.set_options_on_accept_sockets(socket, options)
103
+ socket.instance_variable_set :@zerg_support_factory_options, options
104
+ def socket.accept(*args)
105
+ sock, addr = super
106
+ Zerg::Support::SocketFactory.set_options sock,
107
+ @zerg_support_factory_options
108
+ return sock, addr
109
+ end
110
+ end
111
+
112
+ # Sugar-coat the socket's listen() call with a default value for its argument.
113
+ def self.sugar_socket_listen(socket)
114
+ def socket.listen(*args)
115
+ args = [1000] if args.empty?
116
+ super(*args)
117
+ end
118
+ end
119
+
120
+ # Binds a socket to an address based on the options.
121
+ def self.bind(socket, options)
122
+ socket.bind bind_socket_address(options)
123
+ socket
124
+ end
125
+
126
+ # New inbound socket based on the options.
127
+ def self.new_inbound_socket(options)
128
+ socket = Socket.new Socket::AF_INET, socket_type(options), Socket::PF_UNSPEC
129
+ set_options socket, options
130
+ set_options_on_accept_sockets socket, options
131
+ sugar_socket_listen socket
132
+ bind socket, options
133
+ end
134
+
135
+ # Retrieves possible IP addresses to connect to based on the given options.
136
+ #
137
+ # The retrieval is done via setsockopt.
138
+ def self.addr_infos(options)
139
+ Socket.getaddrinfo connect_host(options), connect_port(options),
140
+ Socket::AF_INET, socket_type(options)
141
+ end
142
+
143
+ # New outbound socket based on an address obtained from getaddrinfo().
144
+ def self.new_outbound_socket_with_addr_info(addr_info)
145
+ Socket.new addr_info[4], addr_info[5], addr_info[6]
146
+ end
147
+
148
+ # Connects a socket to an address obtained from getaddrinfo().
149
+ #
150
+ # Returns the socket for success, or nil if the connection failed.
151
+ def self.connect_with_addr_info(socket, addr_info)
152
+ begin
153
+ socket.connect Socket.pack_sockaddr_in(addr_info[1], addr_info[3])
154
+ socket
155
+ rescue
156
+ nil
157
+ end
158
+ end
159
+
160
+ # New outbound socket based on the options.
161
+ def self.new_outbound_socket(options)
162
+ addr_infos = self.addr_infos options
163
+ addr_infos.each do |addr_info|
164
+ socket = new_outbound_socket_with_addr_info addr_info
165
+ set_options socket, options
166
+ return socket if connect_with_addr_info socket, addr_info
167
+ socket.close rescue nil
168
+ end
169
+ nil
170
+ end
171
+
172
+ # Kitchen-sink socket creation method. The following options are supported:
173
+ # tcp:: forces the use of TCP (overrides the udp option)
174
+ # udp:: selects UDP (the default is TCP)
175
+ # out_port:: the port to connect an outgoing socket to
176
+ # out_host:: the host to connect an outgoing socket to
177
+ # out_addr:: the host:port address to connect an outgoing socket to; the
178
+ # host and port override out_port and out_host, which can be used
179
+ # in conjunction with out_addr to provide default values
180
+ # in_port:: the port to bind a listening socket to
181
+ # in_host:: the host to bind a listening socket to
182
+ # in_addr:: the host:port address to bind a listening socket to; the host
183
+ # and port override in_port and in_host, which can be used in
184
+ # conjunction with in_addr to provide default values
185
+ # no_delay:: disables Nagles' algorithm
186
+ # reuse_addr:: allows binding other sockets to this socket's address
187
+ # reverse_lookup:: enables reverse lookups on connections; this is the Ruby
188
+ # default, but ZergSupport changes it for performance
189
+ def self.socket(options)
190
+ if outbound? options
191
+ new_outbound_socket options
192
+ else
193
+ new_inbound_socket options
194
+ end
195
+ end
196
+ end # class SocketFactory
197
+
198
+ end # namespace Zerg::Support
@@ -0,0 +1,59 @@
1
+ # :nodoc: namespace
2
+ module Zerg::Support::Sockets
3
+
4
+ # Adapts generic Protocol modules to modules that can extend sockets.
5
+ module ProtocolAdapter
6
+ def self.adapter_module(protocol_module, object_name = nil)
7
+ unless object_name
8
+ object_name = /(^|:)([^:]*)Protocol$/.
9
+ match(protocol_module.name)[2].split(/(?=[A-Z])/).join('_').downcase
10
+ end
11
+
12
+ state_class = Class.new StateBase
13
+ state_class.send :include, protocol_module
14
+ state_class.class_eval do
15
+ # Called by the protocol when an entire object is available.
16
+ define_method :"received_#{object_name}" do |object|
17
+ @recv_object_buffer << object
18
+ end
19
+ end
20
+
21
+ adapter = Module.new
22
+ adapter.module_eval do
23
+ # Receives an object from a socket.
24
+ define_method :"recv_#{object_name}" do
25
+ @zerg_protocol_adapter_state ||= state_class.new self
26
+ while @zerg_protocol_adapter_state.recv_object_buffer.length == 0
27
+ data = recv 65536
28
+ return nil if data.length == 0 # Other side closed socket.
29
+ @zerg_protocol_adapter_state.received_bytes data
30
+ end
31
+ @zerg_protocol_adapter_state.recv_object_buffer.shift
32
+ end
33
+
34
+ # Sends an object across a socket.
35
+ define_method :"send_#{object_name}" do |object|
36
+ @zerg_protocol_adapter_state ||= state_class.new self
37
+ @zerg_protocol_adapter_state.send :"send_#{object_name}", object
38
+ end
39
+ end
40
+
41
+ adapter
42
+ end
43
+
44
+ # Base class for the adapter state.
45
+ class StateBase
46
+ attr_reader :recv_object_buffer
47
+ def initialize(target)
48
+ @recv_object_buffer = []
49
+ @target = target
50
+ end
51
+
52
+ # Called by the protocol when an entire object is available.
53
+ def send_bytes(data)
54
+ @target.send data, 0
55
+ end
56
+ end
57
+ end
58
+
59
+ end # namespace Zerg::Support::Sockets
@@ -0,0 +1,60 @@
1
+ # :nodoc: namespace
2
+ module Zerg::Support::Sockets
3
+
4
+ # Mocks the sending end of a Socket connection.
5
+ # The sent data is concatenated in a string available by calling #string.
6
+ class SendMock
7
+ attr_reader :string
8
+
9
+ def initialize
10
+ @string = ''
11
+ end
12
+
13
+ def send(data, flags)
14
+ @string << data
15
+ end
16
+ end # class SendMock
17
+
18
+ # Mocks the receiving end of a Socket connection.
19
+ # The data to be received is passed as an array of strings to the constructor.
20
+ class ReceiveMock
21
+ attr_accessor :strings
22
+ attr_accessor :objects
23
+
24
+ def initialize(strings = [''])
25
+ @strings = strings.kind_of?(String) ? [strings] : strings
26
+ @objects = []
27
+ end
28
+
29
+ def recv(byte_limit)
30
+ bytes = @strings.shift
31
+ return '' unless bytes
32
+ if bytes.length > byte_limit
33
+ @strings.unshift bytes[byte_limit, bytes.length]
34
+ bytes = bytes[0, byte_limit]
35
+ end
36
+ bytes
37
+ end
38
+
39
+ # Declares the name of the object to be received. For instance, a frame
40
+ # protocol would use :frame for name. This generates a receive_frame method,
41
+ # and a frames accessor.
42
+ def self.object_name(name)
43
+ # Calls recv_object until the bytes buffer is drained.
44
+ define_method :replay do
45
+ while @strings.length > 0
46
+ @objects << self.send(:"recv_#{name}")
47
+ end
48
+ loop do
49
+ object = self.send(:"recv_#{name}")
50
+ break unless object
51
+ @objects << object
52
+ end
53
+ self
54
+ end
55
+ return if name == :object
56
+ alias_method :"#{name}s", :objects
57
+ end
58
+ end # class ReceiveMock
59
+
60
+ end # namespace Zerg::Support::Sockets
data/lib/zerg_support.rb CHANGED
@@ -1,4 +1,4 @@
1
- # :nodoc
1
+ # :nodoc: namespace
2
2
  module Zerg
3
3
  end
4
4
 
@@ -10,12 +10,11 @@ require 'rubygems'
10
10
  require 'zerg_support/gems.rb'
11
11
  require 'zerg_support/process.rb'
12
12
  require 'zerg_support/open_ssh.rb'
13
+ require 'zerg_support/socket_factory.rb'
13
14
  require 'zerg_support/spawn.rb'
14
-
15
- # TODO(victor): document this
16
- module Zerg::Support::EventMachine
17
- end
18
-
19
15
  require 'zerg_support/event_machine/connection_mocks.rb'
20
- require 'zerg_support/event_machine/frame_protocol.rb'
21
- require 'zerg_support/event_machine/object_protocol.rb'
16
+ require 'zerg_support/event_machine/protocol_adapter.rb'
17
+ require 'zerg_support/protocols/frame_protocol.rb'
18
+ require 'zerg_support/protocols/object_protocol.rb'
19
+ require 'zerg_support/sockets/protocol_adapter.rb'
20
+ require 'zerg_support/sockets/socket_mocks.rb'
@@ -2,23 +2,12 @@ require 'zerg_support'
2
2
 
3
3
  require 'test/unit'
4
4
 
5
- class TestFrameProtocol < Test::Unit::TestCase
6
- FP = Zerg::Support::EventMachine::FrameProtocol
7
-
8
- # Send mock for frames.
9
- class SendFramesMock < Zerg::Support::EventMachine::SendMock
10
- include FP
11
- end
12
-
13
- # Receive mock for frames.
14
- class ReceiveFramesMock < Zerg::Support::EventMachine::ReceiveMock
15
- include FP
16
- object_name :frame
17
- end
5
+ module FrameProtocolTestMethods
6
+ FP = Zerg::Support::Protocols::FrameProtocol
18
7
 
19
8
  def setup
20
9
  super
21
- @send_mock = SendFramesMock.new
10
+ @send_mock = self.class::SendFramesMock.new
22
11
  end
23
12
 
24
13
  def teardown
@@ -38,12 +27,13 @@ class TestFrameProtocol < Test::Unit::TestCase
38
27
  i += sublen
39
28
  end
40
29
  in_strings << in_string[i..-1] if i < in_string.length
41
- out_frames = ReceiveFramesMock.new(@send_mock.string).replay.frames
30
+ out_frames =
31
+ self.class::ReceiveFramesMock.new(@send_mock.string).replay.frames
42
32
  assert_equal frames, out_frames
43
33
  end
44
34
 
45
35
  def test_empty_frame
46
- continuous_data_test ['']
36
+ continuous_data_test ['']
47
37
  end
48
38
 
49
39
  def test_byte_frame
@@ -88,7 +78,7 @@ class TestFrameProtocol < Test::Unit::TestCase
88
78
  ex_frames = [s2_frame] * s2_count
89
79
 
90
80
  # build cut points in a string
91
- s2_points = [0, 1, 2, 3, 4, 5, 127, 128, 8190, 16381, 16382, 16383]
81
+ s2_points = [1, 2, 3, 4, 5, 127, 128, 8190, 16381, 16382, 16383]
92
82
  cut_points = []
93
83
  0.upto(s2_count - 1) do |i|
94
84
  cut_points += s2_points.map { |p| p + i * s2_string.length }
@@ -101,7 +91,8 @@ class TestFrameProtocol < Test::Unit::TestCase
101
91
  packets = [0...cut_points[i], cut_points[i]...cut_points[j],
102
92
  cut_points[j]...cut_points[k], cut_points[k]..-1].
103
93
  map { |r| send_string[r] }
104
- assert_equal ex_frames, ReceiveFramesMock.new(packets).replay.frames
94
+ assert_equal ex_frames,
95
+ self.class::ReceiveFramesMock.new(packets).replay.frames
105
96
  end
106
97
  end
107
98
  end
@@ -115,5 +106,43 @@ class TestFrameProtocol < Test::Unit::TestCase
115
106
  assert_equal entry.last, FP.encode_natural(entry.first)
116
107
  assert_equal entry.first, FP.decode_natural(entry.last)
117
108
  end
109
+ end
110
+ end
111
+
112
+ class FrameProtocolEventMachineTest < Test::Unit::TestCase
113
+ include FrameProtocolTestMethods
114
+
115
+ ProtocolAdapter = Zerg::Support::EventMachine::ProtocolAdapter
116
+ FP = Zerg::Support::Protocols::FrameProtocol
117
+ FPAdapter = ProtocolAdapter.adapter_module FP
118
+
119
+ # Send mock for frames.
120
+ class SendFramesMock < Zerg::Support::EventMachine::SendMock
121
+ include FPAdapter
122
+ end
123
+
124
+ # Receive mock for frames.
125
+ class ReceiveFramesMock < Zerg::Support::EventMachine::ReceiveMock
126
+ include FPAdapter
127
+ object_name :frame
128
+ end
129
+ end
130
+
131
+ class FrameProtocolSocketsTest < Test::Unit::TestCase
132
+ include FrameProtocolTestMethods
133
+
134
+ ProtocolAdapter = Zerg::Support::Sockets::ProtocolAdapter
135
+ FP = Zerg::Support::Protocols::FrameProtocol
136
+ FPAdapter = ProtocolAdapter.adapter_module FP
137
+
138
+ # Send mock for frames.
139
+ class SendFramesMock < Zerg::Support::Sockets::SendMock
140
+ include FPAdapter
141
+ end
142
+
143
+ # Receive mock for frames.
144
+ class ReceiveFramesMock < Zerg::Support::Sockets::ReceiveMock
145
+ include FPAdapter
146
+ object_name :frame
118
147
  end
119
- end
148
+ end
@@ -3,13 +3,15 @@ require 'test/unit'
3
3
  require 'zerg_support'
4
4
 
5
5
  class ObjectProtocolTest < Test::Unit::TestCase
6
- OP = Zerg::Support::EventMachine::ObjectProtocol
6
+ ProtocolAdapter = Zerg::Support::EventMachine::ProtocolAdapter
7
+ OP = Zerg::Support::Protocols::ObjectProtocol
8
+ OPAdapter = ProtocolAdapter.adapter_module OP
7
9
 
8
10
  class SendObjectMock < Zerg::Support::EventMachine::SendMock
9
- include OP
11
+ include OPAdapter
10
12
  end
11
13
  class ReceiveObjectMock < Zerg::Support::EventMachine::ReceiveMock
12
- include OP
14
+ include OPAdapter
13
15
  object_name :object
14
16
  end
15
17
 
@@ -52,4 +54,4 @@ class ObjectProtocolTest < Test::Unit::TestCase
52
54
  "1234567890",
53
55
  {:command => 'run', :sequence => [1, nil, 2, true, "Q\n"]})
54
56
  end
55
- end
57
+ end
data/test/test_process.rb CHANGED
@@ -4,6 +4,11 @@ require 'test/unit'
4
4
  require 'zerg_support'
5
5
 
6
6
  class TestProcess < Test::Unit::TestCase
7
+ def setup
8
+ super
9
+ Thread.abort_on_exception = true
10
+ end
11
+
7
12
  def teardown
8
13
  @pid_files.each { |f| File.delete f rescue nil } if @pid_files
9
14
  super
@@ -0,0 +1,93 @@
1
+ require 'test/unit'
2
+
3
+ require 'zerg_support'
4
+
5
+
6
+ class SocketFactoryTest < Test::Unit::TestCase
7
+ SF = Zerg::Support::SocketFactory
8
+
9
+ OP = Zerg::Support::Protocols::ObjectProtocol
10
+ OPAdapter = Zerg::Support::Sockets::ProtocolAdapter.adapter_module OP
11
+
12
+ def setup
13
+ Thread.abort_on_exception = true
14
+ end
15
+
16
+ def teardown
17
+
18
+ end
19
+
20
+ def test_host_from_address
21
+ assert_equal nil, SF.host_from_address(nil)
22
+ assert_equal nil, SF.host_from_address(':9000')
23
+ assert_equal '127.0.0.1', SF.host_from_address('127.0.0.1')
24
+ assert_equal '127.0.0.1', SF.host_from_address('127.0.0.1:1234')
25
+ assert_equal 'fe80::1%lo0', SF.host_from_address('fe80::1%lo0')
26
+ assert_equal 'fe80::1%lo0', SF.host_from_address('fe80::1%lo0:19020')
27
+ end
28
+
29
+ def test_port_from_address
30
+ assert_equal nil, SF.port_from_address(nil)
31
+ assert_equal 9000, SF.port_from_address(':9000')
32
+ assert_equal nil, SF.port_from_address('127.0.0.1')
33
+ assert_equal 1234, SF.port_from_address('127.0.0.1:1234')
34
+ assert_equal nil, SF.port_from_address('fe80::1%lo0')
35
+ assert_equal 19020, SF.port_from_address('fe80::1%lo0:19020')
36
+ end
37
+
38
+ def test_inbound
39
+ assert !SF.outbound?(:in_port => 1)
40
+ assert !SF.outbound?(:in_host => '1')
41
+ assert !SF.outbound?(:in_addr => '1')
42
+ assert SF.outbound?(:out_port => 1)
43
+ assert SF.outbound?(:out_host => '1')
44
+ assert SF.outbound?(:out_addr => '1')
45
+ end
46
+
47
+ def test_tcp
48
+ assert SF.tcp?({})
49
+ assert SF.tcp?(:tcp => true)
50
+ assert !SF.tcp?(:udp => true)
51
+ end
52
+
53
+ def _test_connection(server_options, client_options = nil)
54
+ client_options ||= server_options
55
+ test_port = 31996
56
+
57
+ cli_gold = { :request_type => 1, :request_name => "moo" }
58
+ srv_gold = { :response_type => 2, :response_value => [true, 314] }
59
+ cli_hash = nil
60
+
61
+ # Server thread.
62
+ Thread.new do
63
+ server = SF.socket({:in_addr => ":#{test_port}"}.merge server_options)
64
+ server.listen
65
+ serv_client, client_addrinfo = server.accept
66
+ serv_client.extend OPAdapter
67
+ cli_hash = serv_client.recv_object
68
+ serv_client.send_object srv_gold
69
+ serv_client.close
70
+
71
+ server.close
72
+ end
73
+
74
+ # Client.
75
+ client = SF.socket({:out_addr => "localhost:#{test_port}"}.
76
+ merge(client_options))
77
+ client.extend OPAdapter
78
+ client.send_object cli_gold
79
+ srv_hash = client.recv_object
80
+ client.close
81
+
82
+ # Checks
83
+ assert_equal cli_gold, cli_hash, "Client -> server failed"
84
+ assert_equal srv_gold, srv_hash, "Server -> client failed"
85
+ end
86
+
87
+ def test_connection
88
+ _test_connection({:no_delay => true})
89
+ _test_connection({:reuse_addr => true})
90
+
91
+ # TODO(costan): fix UDP at some point
92
+ end
93
+ end
data/test/test_spawn.rb CHANGED
@@ -15,6 +15,7 @@ class TestSpawn < Test::Unit::TestCase
15
15
 
16
16
  def setup
17
17
  super
18
+ Thread.abort_on_exception = true
18
19
  @in_file = temp_file
19
20
  @out_file = temp_file
20
21
  end
data/zerg_support.gemspec CHANGED
@@ -2,27 +2,26 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{zerg_support}
5
- s.version = "0.0.9"
5
+ s.version = "0.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Victor Costan"]
9
- s.date = %q{2009-03-28}
9
+ s.date = %q{2009-06-02}
10
10
  s.description = %q{Support libraries used by Zergling.Net deployment code.}
11
11
  s.email = %q{victor@zergling.net}
12
- s.extra_rdoc_files = ["CHANGELOG", "lib/zerg_support/event_machine/connection_mocks.rb", "lib/zerg_support/event_machine/frame_protocol.rb", "lib/zerg_support/event_machine/object_protocol.rb", "lib/zerg_support/gems.rb", "lib/zerg_support/open_ssh.rb", "lib/zerg_support/process.rb", "lib/zerg_support/spawn.rb", "lib/zerg_support.rb", "LICENSE", "README"]
13
- s.files = ["CHANGELOG", "lib/zerg_support/event_machine/connection_mocks.rb", "lib/zerg_support/event_machine/frame_protocol.rb", "lib/zerg_support/event_machine/object_protocol.rb", "lib/zerg_support/gems.rb", "lib/zerg_support/open_ssh.rb", "lib/zerg_support/process.rb", "lib/zerg_support/spawn.rb", "lib/zerg_support.rb", "LICENSE", "Manifest", "Rakefile", "README", "RUBYFORGE", "test/fork_tree.rb", "test/test_connection_mocks.rb", "test/test_frame_protocol.rb", "test/test_gems.rb", "test/test_object_protocol.rb", "test/test_open_ssh.rb", "test/test_process.rb", "test/test_spawn.rb", "zerg_support.gemspec"]
14
- s.has_rdoc = true
12
+ s.extra_rdoc_files = ["CHANGELOG", "lib/zerg_support/event_machine/connection_mocks.rb", "lib/zerg_support/event_machine/protocol_adapter.rb", "lib/zerg_support/gems.rb", "lib/zerg_support/open_ssh.rb", "lib/zerg_support/process.rb", "lib/zerg_support/protocols/frame_protocol.rb", "lib/zerg_support/protocols/object_protocol.rb", "lib/zerg_support/socket_factory.rb", "lib/zerg_support/sockets/protocol_adapter.rb", "lib/zerg_support/sockets/socket_mocks.rb", "lib/zerg_support/spawn.rb", "lib/zerg_support.rb", "LICENSE", "README"]
13
+ s.files = ["CHANGELOG", "lib/zerg_support/event_machine/connection_mocks.rb", "lib/zerg_support/event_machine/protocol_adapter.rb", "lib/zerg_support/gems.rb", "lib/zerg_support/open_ssh.rb", "lib/zerg_support/process.rb", "lib/zerg_support/protocols/frame_protocol.rb", "lib/zerg_support/protocols/object_protocol.rb", "lib/zerg_support/socket_factory.rb", "lib/zerg_support/sockets/protocol_adapter.rb", "lib/zerg_support/sockets/socket_mocks.rb", "lib/zerg_support/spawn.rb", "lib/zerg_support.rb", "LICENSE", "Manifest", "Rakefile", "README", "RUBYFORGE", "test/fork_tree.rb", "test/test_connection_mocks.rb", "test/test_frame_protocol.rb", "test/test_gems.rb", "test/test_object_protocol.rb", "test/test_open_ssh.rb", "test/test_process.rb", "test/test_socket_factory.rb", "test/test_spawn.rb", "zerg_support.gemspec"]
15
14
  s.homepage = %q{http://www.zergling.net}
16
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Zerg_support", "--main", "README"]
17
16
  s.require_paths = ["lib"]
18
17
  s.rubyforge_project = %q{zerglings}
19
- s.rubygems_version = %q{1.3.1}
18
+ s.rubygems_version = %q{1.3.4}
20
19
  s.summary = %q{Support libraries used by Zergling.Net deployment code.}
21
- s.test_files = ["test/test_connection_mocks.rb", "test/test_frame_protocol.rb", "test/test_gems.rb", "test/test_object_protocol.rb", "test/test_open_ssh.rb", "test/test_process.rb", "test/test_spawn.rb"]
20
+ s.test_files = ["test/test_connection_mocks.rb", "test/test_frame_protocol.rb", "test/test_gems.rb", "test/test_object_protocol.rb", "test/test_open_ssh.rb", "test/test_process.rb", "test/test_socket_factory.rb", "test/test_spawn.rb"]
22
21
 
23
22
  if s.respond_to? :specification_version then
24
23
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
- s.specification_version = 2
24
+ s.specification_version = 3
26
25
 
27
26
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
27
  s.add_development_dependency(%q<echoe>, [">= 3.0.2"])
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zerg_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: "0.1"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Costan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-28 00:00:00 -04:00
12
+ date: 2009-06-02 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -51,11 +51,15 @@ extensions: []
51
51
  extra_rdoc_files:
52
52
  - CHANGELOG
53
53
  - lib/zerg_support/event_machine/connection_mocks.rb
54
- - lib/zerg_support/event_machine/frame_protocol.rb
55
- - lib/zerg_support/event_machine/object_protocol.rb
54
+ - lib/zerg_support/event_machine/protocol_adapter.rb
56
55
  - lib/zerg_support/gems.rb
57
56
  - lib/zerg_support/open_ssh.rb
58
57
  - lib/zerg_support/process.rb
58
+ - lib/zerg_support/protocols/frame_protocol.rb
59
+ - lib/zerg_support/protocols/object_protocol.rb
60
+ - lib/zerg_support/socket_factory.rb
61
+ - lib/zerg_support/sockets/protocol_adapter.rb
62
+ - lib/zerg_support/sockets/socket_mocks.rb
59
63
  - lib/zerg_support/spawn.rb
60
64
  - lib/zerg_support.rb
61
65
  - LICENSE
@@ -63,11 +67,15 @@ extra_rdoc_files:
63
67
  files:
64
68
  - CHANGELOG
65
69
  - lib/zerg_support/event_machine/connection_mocks.rb
66
- - lib/zerg_support/event_machine/frame_protocol.rb
67
- - lib/zerg_support/event_machine/object_protocol.rb
70
+ - lib/zerg_support/event_machine/protocol_adapter.rb
68
71
  - lib/zerg_support/gems.rb
69
72
  - lib/zerg_support/open_ssh.rb
70
73
  - lib/zerg_support/process.rb
74
+ - lib/zerg_support/protocols/frame_protocol.rb
75
+ - lib/zerg_support/protocols/object_protocol.rb
76
+ - lib/zerg_support/socket_factory.rb
77
+ - lib/zerg_support/sockets/protocol_adapter.rb
78
+ - lib/zerg_support/sockets/socket_mocks.rb
71
79
  - lib/zerg_support/spawn.rb
72
80
  - lib/zerg_support.rb
73
81
  - LICENSE
@@ -82,10 +90,13 @@ files:
82
90
  - test/test_object_protocol.rb
83
91
  - test/test_open_ssh.rb
84
92
  - test/test_process.rb
93
+ - test/test_socket_factory.rb
85
94
  - test/test_spawn.rb
86
95
  - zerg_support.gemspec
87
96
  has_rdoc: true
88
97
  homepage: http://www.zergling.net
98
+ licenses: []
99
+
89
100
  post_install_message:
90
101
  rdoc_options:
91
102
  - --line-numbers
@@ -111,9 +122,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
122
  requirements: []
112
123
 
113
124
  rubyforge_project: zerglings
114
- rubygems_version: 1.3.1
125
+ rubygems_version: 1.3.4
115
126
  signing_key:
116
- specification_version: 2
127
+ specification_version: 3
117
128
  summary: Support libraries used by Zergling.Net deployment code.
118
129
  test_files:
119
130
  - test/test_connection_mocks.rb
@@ -122,4 +133,5 @@ test_files:
122
133
  - test/test_object_protocol.rb
123
134
  - test/test_open_ssh.rb
124
135
  - test/test_process.rb
136
+ - test/test_socket_factory.rb
125
137
  - test/test_spawn.rb