gqtp 1.0.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/Gemfile +21 -0
- data/README.md +76 -0
- data/Rakefile +44 -0
- data/bin/gqtp-proxy +77 -0
- data/doc/text/lgpl-2.1.txt +502 -0
- data/doc/text/news.md +5 -0
- data/gqtp.gemspec +52 -0
- data/lib/gqtp/client.rb +86 -0
- data/lib/gqtp/connection/coolio.rb +133 -0
- data/lib/gqtp/connection/synchronous.rb +108 -0
- data/lib/gqtp/connection/thread.rb +123 -0
- data/lib/gqtp/error.rb +24 -0
- data/lib/gqtp/header.rb +190 -0
- data/lib/gqtp/parser.rb +173 -0
- data/lib/gqtp/proxy.rb +74 -0
- data/lib/gqtp/server.rb +99 -0
- data/lib/gqtp/version.rb +21 -0
- data/lib/gqtp.rb +22 -0
- data/test/run-test.rb +32 -0
- data/test/test-client.rb +68 -0
- data/test/test-header.rb +49 -0
- data/test/test-parser.rb +131 -0
- metadata +177 -0
data/lib/gqtp/parser.rb
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "gqtp/error"
|
20
|
+
require "gqtp/header"
|
21
|
+
|
22
|
+
module GQTP
|
23
|
+
class ParseError < Error
|
24
|
+
end
|
25
|
+
|
26
|
+
class Parser
|
27
|
+
class << self
|
28
|
+
def parse(data, &block)
|
29
|
+
if block_given?
|
30
|
+
event_parse(data, &block)
|
31
|
+
else
|
32
|
+
stand_alone_parse(data)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def event_parse(data)
|
38
|
+
parser = new
|
39
|
+
|
40
|
+
parser.on_header do |header|
|
41
|
+
yield(:on_header, header)
|
42
|
+
end
|
43
|
+
parser.on_body do |chunk|
|
44
|
+
yield(:on_body, chunk)
|
45
|
+
end
|
46
|
+
parser.on_complete do
|
47
|
+
yield(:on_complete)
|
48
|
+
end
|
49
|
+
|
50
|
+
consume_data(parser, data)
|
51
|
+
end
|
52
|
+
|
53
|
+
def stand_alone_parse(data)
|
54
|
+
received_header = nil
|
55
|
+
body = "".force_encoding("ASCII-8BIT")
|
56
|
+
completed = false
|
57
|
+
|
58
|
+
parser = new
|
59
|
+
parser.on_header do |header|
|
60
|
+
received_header = header
|
61
|
+
end
|
62
|
+
parser.on_body do |chunk|
|
63
|
+
body << chunk
|
64
|
+
end
|
65
|
+
parser.on_complete do
|
66
|
+
completed = true
|
67
|
+
end
|
68
|
+
|
69
|
+
consume_data(parser, data)
|
70
|
+
raise ParseError, "not completed: <#{data.inspect}>" unless completed
|
71
|
+
|
72
|
+
[received_header, body]
|
73
|
+
end
|
74
|
+
|
75
|
+
def consume_data(parser, data)
|
76
|
+
if data.respond_to?(:each)
|
77
|
+
data.each do |chunk|
|
78
|
+
parser << chunk
|
79
|
+
end
|
80
|
+
else
|
81
|
+
parser << data
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :header
|
87
|
+
def initialize
|
88
|
+
reset
|
89
|
+
initialize_hooks
|
90
|
+
end
|
91
|
+
|
92
|
+
def <<(chunk)
|
93
|
+
if @header.nil?
|
94
|
+
parse_header(chunk)
|
95
|
+
else
|
96
|
+
parse_body(chunk)
|
97
|
+
end
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
# @overload on_header(header)
|
102
|
+
# @overload on_header {|header| }
|
103
|
+
def on_header(*arguments, &block)
|
104
|
+
if block_given?
|
105
|
+
@on_header_hook = block
|
106
|
+
else
|
107
|
+
@on_header_hook.call(*arguments) if @on_header_hook
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @overload on_body(chunk)
|
112
|
+
# @overload on_body {|chunk| }
|
113
|
+
def on_body(*arguments, &block)
|
114
|
+
if block_given?
|
115
|
+
@on_body_hook = block
|
116
|
+
else
|
117
|
+
@on_body_hook.call(*arguments) if @on_body_hook
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @overload on_complete
|
122
|
+
# @overload on_complete { }
|
123
|
+
def on_complete(&block)
|
124
|
+
if block_given?
|
125
|
+
@on_complete_hook = block
|
126
|
+
else
|
127
|
+
@on_complete_hook.call if @on_complete_hook
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def reset
|
133
|
+
@buffer = "".force_encoding("ASCII-8BIT")
|
134
|
+
@header = nil
|
135
|
+
@body_size = 0
|
136
|
+
end
|
137
|
+
|
138
|
+
def initialize_hooks
|
139
|
+
@on_header_hook = nil
|
140
|
+
@on_body_hook = nil
|
141
|
+
@on_complete_hook = nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def parse_header(chunk)
|
145
|
+
@buffer << chunk
|
146
|
+
return if @buffer.bytesize < Header.size
|
147
|
+
@header = Header.parse(@buffer)
|
148
|
+
on_header(@header)
|
149
|
+
buffer = @buffer
|
150
|
+
@buffer = nil
|
151
|
+
if buffer.bytesize > Header.size
|
152
|
+
parse_body(buffer[Header.size..-1])
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def parse_body(chunk)
|
157
|
+
@body_size += chunk.bytesize
|
158
|
+
if @body_size < @header.size
|
159
|
+
on_body(chunk)
|
160
|
+
elsif @body_size == @header.size
|
161
|
+
on_body(chunk)
|
162
|
+
on_complete
|
163
|
+
reset
|
164
|
+
else
|
165
|
+
rest_body_size = @header.size - (@body_size - chunk.bytesize)
|
166
|
+
on_body(chunk[0, rest_body_size])
|
167
|
+
on_complete
|
168
|
+
reset
|
169
|
+
self << chunk[rest_body_size..-1]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
data/lib/gqtp/proxy.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "gqtp/server"
|
20
|
+
|
21
|
+
module GQTP
|
22
|
+
class Proxy
|
23
|
+
attr_accessor :listen_address, :listen_port
|
24
|
+
attr_accessor :upstream_address, :upstream_port
|
25
|
+
def initialize(options={})
|
26
|
+
@options = options.dup
|
27
|
+
@listen_address = @options[:listen_address] || "0.0.0.0"
|
28
|
+
@listen_port = @options[:listen_port] || 10041
|
29
|
+
@upstream_address = @options[:upstream_address] || "127.0.0.1"
|
30
|
+
@upstream_port = @options[:upstream_port] || 10041
|
31
|
+
@connection = @options[:connection] || :thread
|
32
|
+
@server = Server.new(:address => @listen_address,
|
33
|
+
:port => @listen_port,
|
34
|
+
:connection => @connection)
|
35
|
+
end
|
36
|
+
|
37
|
+
def run
|
38
|
+
@server.on_connect do |client|
|
39
|
+
create_connection
|
40
|
+
end
|
41
|
+
@server.on_request do |request, client, connection|
|
42
|
+
connection.write(request.header.pack, request.body) do
|
43
|
+
read_header_request = connection.read(Header.size) do |header|
|
44
|
+
response_header = Header.parse(header)
|
45
|
+
read_body_request = connection.read(response_header.size) do |body|
|
46
|
+
client.write(header, body) do
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@server.run
|
53
|
+
end
|
54
|
+
|
55
|
+
def shutdown
|
56
|
+
@server.shutdown
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def create_connection
|
61
|
+
begin
|
62
|
+
require "gqtp/connection/#{@connection}"
|
63
|
+
rescue LoadError
|
64
|
+
raise "unknown connection: <#{@connection.inspect}>"
|
65
|
+
end
|
66
|
+
|
67
|
+
require "gqtp/connection/#{@connection}"
|
68
|
+
module_name = @connection.to_s.capitalize
|
69
|
+
connection_module = GQTP::Connection::const_get(module_name)
|
70
|
+
connection_module::Client.new(:address => @upstream_address,
|
71
|
+
:port => @upstream_port)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/gqtp/server.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "gqtp/header"
|
20
|
+
|
21
|
+
module GQTP
|
22
|
+
class Server
|
23
|
+
attr_accessor :address, :port
|
24
|
+
def initialize(options={})
|
25
|
+
@options = options.dup
|
26
|
+
@options[:address] ||= "0.0.0.0"
|
27
|
+
@options[:port] ||= 10041
|
28
|
+
@on_request = nil
|
29
|
+
@on_connect = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def run
|
33
|
+
@connection = create_connection
|
34
|
+
@connection.run do |client|
|
35
|
+
process_request(client, on_connect(client))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def shutdown
|
40
|
+
@connection.shutdown
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_connect(*arguments, &block)
|
44
|
+
if block_given?
|
45
|
+
@on_connect = block
|
46
|
+
else
|
47
|
+
client, = arguments
|
48
|
+
if @on_connect
|
49
|
+
@on_connect.call(client)
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_request(*arguments, &block)
|
57
|
+
if block_given?
|
58
|
+
@on_request = block
|
59
|
+
else
|
60
|
+
request, client, connect_info = arguments
|
61
|
+
@on_request.call(request, client, connect_info)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def create_connection
|
67
|
+
connection = @options[:connection] || :thread
|
68
|
+
|
69
|
+
begin
|
70
|
+
require "gqtp/connection/#{connection}"
|
71
|
+
rescue LoadError
|
72
|
+
raise "unknown connection: <#{connection.inspect}>"
|
73
|
+
end
|
74
|
+
|
75
|
+
module_name = connection.to_s.capitalize
|
76
|
+
connection_module = GQTP::Connection::const_get(module_name)
|
77
|
+
connection_module::Server.new(@options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def process_request(client, connect_info)
|
81
|
+
read_header_request = client.read(Header.size) do |header|
|
82
|
+
request_header = Header.parse(header)
|
83
|
+
read_body_request = client.read(request_header.size) do |body|
|
84
|
+
request = Request.new(request_header, body)
|
85
|
+
on_request(request, client, connect_info)
|
86
|
+
process_request(client, connect_info)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Request
|
92
|
+
attr_reader :header, :body
|
93
|
+
def initialize(header, body)
|
94
|
+
@header = header
|
95
|
+
@body = body
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/gqtp/version.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
module GQTP
|
20
|
+
VERSION = "1.0.0"
|
21
|
+
end
|
data/lib/gqtp.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "gqtp/version"
|
20
|
+
require "gqtp/client"
|
21
|
+
require "gqtp/server"
|
22
|
+
require "gqtp/proxy"
|
data/test/run-test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
$VERBOSE = true
|
20
|
+
|
21
|
+
base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
22
|
+
lib_dir = File.join(base_dir, "lib")
|
23
|
+
test_dir = File.join(base_dir, "test")
|
24
|
+
|
25
|
+
$LOAD_PATH.unshift(lib_dir)
|
26
|
+
|
27
|
+
require "test-unit"
|
28
|
+
require "test/unit/notify"
|
29
|
+
|
30
|
+
Thread.abort_on_exception = true
|
31
|
+
|
32
|
+
exit Test::Unit::AutoRunner.run(true, test_dir)
|
data/test/test-client.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "socket"
|
20
|
+
|
21
|
+
require "gqtp/client"
|
22
|
+
|
23
|
+
class ClientTest < Test::Unit::TestCase
|
24
|
+
def setup
|
25
|
+
@address = "127.0.0.1"
|
26
|
+
@server = TCPServer.new(@address, 0)
|
27
|
+
@port = @server.addr[1]
|
28
|
+
|
29
|
+
@request_body = nil
|
30
|
+
@response_body = nil
|
31
|
+
@thread = Thread.new do
|
32
|
+
client = @server.accept
|
33
|
+
@server.close
|
34
|
+
|
35
|
+
header = GQTP::Header.parse(client.read(GQTP::Header.size))
|
36
|
+
@request_body = client.read(header.size)
|
37
|
+
|
38
|
+
response_header = GQTP::Header.new
|
39
|
+
response_header.size = @response_body.bytesize
|
40
|
+
client.write(response_header.pack)
|
41
|
+
client.write(@response_body)
|
42
|
+
client.close
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def teardown
|
47
|
+
@thread.kill
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_sync
|
51
|
+
@response_body = "[false]"
|
52
|
+
client = GQTP::Client.new(:address => @address, :port => @port)
|
53
|
+
client.send("status")
|
54
|
+
header, body = client.read
|
55
|
+
assert_equal(["status", @response_body.bytesize, @response_body],
|
56
|
+
[@request_body, header.size, body])
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_async
|
60
|
+
@response_body = "[false]"
|
61
|
+
client = GQTP::Client.new(:address => @address, :port => @port)
|
62
|
+
request = client.send("status") do |header, body|
|
63
|
+
assert_equal(["status", @response_body.bytesize, @response_body],
|
64
|
+
[@request_body, header.size, body])
|
65
|
+
end
|
66
|
+
request.wait
|
67
|
+
end
|
68
|
+
end
|
data/test/test-header.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "gqtp/parser"
|
20
|
+
|
21
|
+
class HeaderTest < Test::Unit::TestCase
|
22
|
+
class EqualTest < self
|
23
|
+
def test_true
|
24
|
+
assert_equal(GQTP::Header.new,
|
25
|
+
GQTP::Header.new)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_false
|
29
|
+
header_size_0 = GQTP::Header.new
|
30
|
+
header_size_1 = GQTP::Header.new
|
31
|
+
header_size_1.size = 1
|
32
|
+
assert_not_equal(header_size_0, header_size_1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class InitializeTest < self
|
37
|
+
def test_hash
|
38
|
+
header = GQTP::Header.new(:size => 29)
|
39
|
+
assert_equal(29, header.size)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_block
|
43
|
+
header = GQTP::Header.new do |h|
|
44
|
+
h.size = 29
|
45
|
+
end
|
46
|
+
assert_equal(29, header.size)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/test/test-parser.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License as published by the Free Software Foundation; either
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
9
|
+
#
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# Lesser General Public License for more details.
|
14
|
+
#
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
16
|
+
# License along with this library; if not, write to the Free Software
|
17
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
+
|
19
|
+
require "gqtp/parser"
|
20
|
+
|
21
|
+
class ParserTest < Test::Unit::TestCase
|
22
|
+
def setup
|
23
|
+
@parser = GQTP::Parser.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_on_header
|
27
|
+
received_header = nil
|
28
|
+
@parser.on_header do |header|
|
29
|
+
received_header = header
|
30
|
+
end
|
31
|
+
|
32
|
+
header = GQTP::Header.new
|
33
|
+
packed_header = header.pack
|
34
|
+
@parser << packed_header[0..-2]
|
35
|
+
assert_nil(received_header)
|
36
|
+
@parser << packed_header[-1..-1]
|
37
|
+
assert_equal(header, received_header)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_on_body
|
41
|
+
received_data = ""
|
42
|
+
@parser.on_body do |chunk|
|
43
|
+
received_data << chunk
|
44
|
+
end
|
45
|
+
|
46
|
+
data = "status"
|
47
|
+
header = GQTP::Header.new
|
48
|
+
header.size = data.bytesize
|
49
|
+
|
50
|
+
@parser << header.pack
|
51
|
+
assert_equal("", received_data)
|
52
|
+
|
53
|
+
@parser << data[0..-2]
|
54
|
+
assert_equal(data[0..-2], received_data)
|
55
|
+
|
56
|
+
@parser << data[-1..-1]
|
57
|
+
assert_equal(data, received_data)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_on_complete
|
61
|
+
completed = false
|
62
|
+
@parser.on_complete do
|
63
|
+
completed = true
|
64
|
+
end
|
65
|
+
|
66
|
+
data = "status"
|
67
|
+
header = GQTP::Header.new
|
68
|
+
header.size = data.bytesize
|
69
|
+
|
70
|
+
@parser << header.pack << data[0..-2]
|
71
|
+
assert_false(completed)
|
72
|
+
|
73
|
+
@parser << data[-1..-1]
|
74
|
+
assert_true(completed)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_parse_twice
|
78
|
+
body = "status"
|
79
|
+
header = GQTP::Header.new
|
80
|
+
header.size = body.bytesize
|
81
|
+
|
82
|
+
n_completed = 0
|
83
|
+
@parser.on_complete do
|
84
|
+
n_completed += 1
|
85
|
+
end
|
86
|
+
@parser << ((header.pack + body) * 2)
|
87
|
+
assert_equal(2, n_completed)
|
88
|
+
end
|
89
|
+
|
90
|
+
class ParseTest < self
|
91
|
+
def test_event
|
92
|
+
body = "status"
|
93
|
+
header = GQTP::Header.new
|
94
|
+
header.size = body.bytesize
|
95
|
+
|
96
|
+
events = []
|
97
|
+
GQTP::Parser.parse([header.pack, body]) do |event_type, *arguments|
|
98
|
+
events << [event_type, arguments]
|
99
|
+
end
|
100
|
+
assert_equal([
|
101
|
+
[:on_header, [header]],
|
102
|
+
[:on_body, [body]],
|
103
|
+
[:on_complete, []],
|
104
|
+
],
|
105
|
+
events)
|
106
|
+
end
|
107
|
+
|
108
|
+
class StandAloneTest < self
|
109
|
+
def test_success
|
110
|
+
body = "status"
|
111
|
+
header = GQTP::Header.new
|
112
|
+
header.size = body.bytesize
|
113
|
+
|
114
|
+
parsed_header, parsed_body = GQTP::Parser.parse([header.pack, body])
|
115
|
+
assert_equal([ header, body],
|
116
|
+
[parsed_header, parsed_body])
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_not_completed
|
120
|
+
header = GQTP::Header.new
|
121
|
+
not_completed_data = header.pack[0..1]
|
122
|
+
|
123
|
+
message = "not completed: <#{not_completed_data.inspect}>"
|
124
|
+
exception = GQTP::ParseError.new(message)
|
125
|
+
assert_raise(exception) do
|
126
|
+
GQTP::Parser.parse(not_completed_data)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|