avro-jruby 1.7.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/Manifest +23 -0
- data/Rakefile +63 -0
- data/avro-jruby.gemspec +34 -0
- data/interop/test_interop.rb +41 -0
- data/lib/avro.rb +42 -0
- data/lib/avro/collect_hash.rb +25 -0
- data/lib/avro/data_file.rb +342 -0
- data/lib/avro/io.rb +615 -0
- data/lib/avro/ipc.rb +550 -0
- data/lib/avro/protocol.rb +161 -0
- data/lib/avro/schema.rb +405 -0
- data/test/random_data.rb +90 -0
- data/test/sample_ipc_client.rb +85 -0
- data/test/sample_ipc_http_client.rb +84 -0
- data/test/sample_ipc_http_server.rb +79 -0
- data/test/sample_ipc_server.rb +92 -0
- data/test/test_datafile.rb +188 -0
- data/test/test_help.rb +23 -0
- data/test/test_io.rb +393 -0
- data/test/test_protocol.rb +199 -0
- data/test/test_schema.rb +134 -0
- data/test/test_socket_transport.rb +40 -0
- data/test/tool.rb +144 -0
- metadata +103 -0
data/test/random_data.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
class RandomData
|
19
|
+
def initialize(schm, seed=nil)
|
20
|
+
srand(seed) if seed
|
21
|
+
@seed = seed
|
22
|
+
@schm = schm
|
23
|
+
end
|
24
|
+
|
25
|
+
def next
|
26
|
+
nextdata(@schm)
|
27
|
+
end
|
28
|
+
|
29
|
+
def nextdata(schm, d=0)
|
30
|
+
case schm.type_sym
|
31
|
+
when :boolean
|
32
|
+
rand > 0.5
|
33
|
+
when :string
|
34
|
+
randstr()
|
35
|
+
when :int
|
36
|
+
rand(Avro::Schema::INT_MAX_VALUE - Avro::Schema::INT_MIN_VALUE) + Avro::Schema::INT_MIN_VALUE
|
37
|
+
when :long
|
38
|
+
rand(Avro::Schema::LONG_MAX_VALUE - Avro::Schema::LONG_MIN_VALUE) + Avro::Schema::LONG_MIN_VALUE
|
39
|
+
when :float
|
40
|
+
(-1024 + 2048 * rand).round.to_f
|
41
|
+
when :double
|
42
|
+
Avro::Schema::LONG_MIN_VALUE + (Avro::Schema::LONG_MAX_VALUE - Avro::Schema::LONG_MIN_VALUE) * rand
|
43
|
+
when :bytes
|
44
|
+
randstr(BYTEPOOL)
|
45
|
+
when :null
|
46
|
+
nil
|
47
|
+
when :array
|
48
|
+
arr = []
|
49
|
+
len = rand(5) + 2 - d
|
50
|
+
len = 0 if len < 0
|
51
|
+
len.times{ arr << nextdata(schm.items, d+1) }
|
52
|
+
arr
|
53
|
+
when :map
|
54
|
+
map = {}
|
55
|
+
len = rand(5) + 2 - d
|
56
|
+
len = 0 if len < 0
|
57
|
+
len.times do
|
58
|
+
map[nextdata(Avro::Schema::PrimitiveSchema.new(:string))] = nextdata(schm.values, d+1)
|
59
|
+
end
|
60
|
+
map
|
61
|
+
when :record, :error
|
62
|
+
m = {}
|
63
|
+
schm.fields.each do |field|
|
64
|
+
m[field.name] = nextdata(field.type, d+1)
|
65
|
+
end
|
66
|
+
m
|
67
|
+
when :union
|
68
|
+
types = schm.schemas
|
69
|
+
nextdata(types[rand(types.size)], d)
|
70
|
+
when :enum
|
71
|
+
symbols = schm.symbols
|
72
|
+
len = symbols.size
|
73
|
+
return nil if len == 0
|
74
|
+
symbols[rand(len)]
|
75
|
+
when :fixed
|
76
|
+
f = ""
|
77
|
+
schm.size.times { f << BYTEPOOL[rand(BYTEPOOL.size), 1] }
|
78
|
+
f
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
CHARPOOL = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
|
83
|
+
BYTEPOOL = '12345abcd'
|
84
|
+
|
85
|
+
def randstr(chars=CHARPOOL, length=20)
|
86
|
+
str = ''
|
87
|
+
rand(length+1).times { str << chars[rand(chars.size)] }
|
88
|
+
str
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'socket'
|
19
|
+
require 'avro'
|
20
|
+
|
21
|
+
MAIL_PROTOCOL_JSON = <<-JSON
|
22
|
+
{"namespace": "example.proto",
|
23
|
+
"protocol": "Mail",
|
24
|
+
|
25
|
+
"types": [
|
26
|
+
{"name": "Message", "type": "record",
|
27
|
+
"fields": [
|
28
|
+
{"name": "to", "type": "string"},
|
29
|
+
{"name": "from", "type": "string"},
|
30
|
+
{"name": "body", "type": "string"}
|
31
|
+
]
|
32
|
+
}
|
33
|
+
],
|
34
|
+
|
35
|
+
"messages": {
|
36
|
+
"send": {
|
37
|
+
"request": [{"name": "message", "type": "Message"}],
|
38
|
+
"response": "string"
|
39
|
+
},
|
40
|
+
"replay": {
|
41
|
+
"request": [],
|
42
|
+
"response": "string"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
JSON
|
47
|
+
|
48
|
+
MAIL_PROTOCOL = Avro::Protocol.parse(MAIL_PROTOCOL_JSON)
|
49
|
+
|
50
|
+
def make_requestor(server_address, port, protocol)
|
51
|
+
sock = TCPSocket.new(server_address, port)
|
52
|
+
client = Avro::IPC::SocketTransport.new(sock)
|
53
|
+
Avro::IPC::Requestor.new(protocol, client)
|
54
|
+
end
|
55
|
+
|
56
|
+
if $0 == __FILE__
|
57
|
+
if ![3, 4].include?(ARGV.length)
|
58
|
+
raise "Usage: <to> <from> <body> [<count>]"
|
59
|
+
end
|
60
|
+
|
61
|
+
# client code - attach to the server and send a message
|
62
|
+
# fill in the Message record
|
63
|
+
message = {
|
64
|
+
'to' => ARGV[0],
|
65
|
+
'from' => ARGV[1],
|
66
|
+
'body' => ARGV[2]
|
67
|
+
}
|
68
|
+
|
69
|
+
num_messages = (ARGV[3] || 1).to_i
|
70
|
+
|
71
|
+
# build the parameters for the request
|
72
|
+
params = {'message' => message}
|
73
|
+
|
74
|
+
# send the requests and print the result
|
75
|
+
num_messages.times do
|
76
|
+
requestor = make_requestor('localhost', 9090, MAIL_PROTOCOL)
|
77
|
+
result = requestor.request('send', params)
|
78
|
+
puts("Result: " + result)
|
79
|
+
end
|
80
|
+
|
81
|
+
# try out a replay message
|
82
|
+
requestor = make_requestor('localhost', 9090, MAIL_PROTOCOL)
|
83
|
+
result = requestor.request('replay', {})
|
84
|
+
puts("Replay Result: " + result)
|
85
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'socket'
|
19
|
+
require 'avro'
|
20
|
+
|
21
|
+
MAIL_PROTOCOL_JSON = <<-JSON
|
22
|
+
{"namespace": "example.proto",
|
23
|
+
"protocol": "Mail",
|
24
|
+
|
25
|
+
"types": [
|
26
|
+
{"name": "Message", "type": "record",
|
27
|
+
"fields": [
|
28
|
+
{"name": "to", "type": "string"},
|
29
|
+
{"name": "from", "type": "string"},
|
30
|
+
{"name": "body", "type": "string"}
|
31
|
+
]
|
32
|
+
}
|
33
|
+
],
|
34
|
+
|
35
|
+
"messages": {
|
36
|
+
"send": {
|
37
|
+
"request": [{"name": "message", "type": "Message"}],
|
38
|
+
"response": "string"
|
39
|
+
},
|
40
|
+
"replay": {
|
41
|
+
"request": [],
|
42
|
+
"response": "string"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
JSON
|
47
|
+
|
48
|
+
MAIL_PROTOCOL = Avro::Protocol.parse(MAIL_PROTOCOL_JSON)
|
49
|
+
|
50
|
+
def make_requestor(server_address, port, protocol)
|
51
|
+
transport = Avro::IPC::HTTPTransceiver.new(server_address, port)
|
52
|
+
Avro::IPC::Requestor.new(protocol, transport)
|
53
|
+
end
|
54
|
+
|
55
|
+
if $0 == __FILE__
|
56
|
+
if ![3, 4].include?(ARGV.length)
|
57
|
+
raise "Usage: <to> <from> <body> [<count>]"
|
58
|
+
end
|
59
|
+
|
60
|
+
# client code - attach to the server and send a message
|
61
|
+
# fill in the Message record
|
62
|
+
message = {
|
63
|
+
'to' => ARGV[0],
|
64
|
+
'from' => ARGV[1],
|
65
|
+
'body' => ARGV[2]
|
66
|
+
}
|
67
|
+
|
68
|
+
num_messages = (ARGV[3] || 1).to_i
|
69
|
+
|
70
|
+
# build the parameters for the request
|
71
|
+
params = {'message' => message}
|
72
|
+
# send the requests and print the result
|
73
|
+
|
74
|
+
num_messages.times do
|
75
|
+
requestor = make_requestor('localhost', 9090, MAIL_PROTOCOL)
|
76
|
+
result = requestor.request('send', params)
|
77
|
+
puts("Result: " + result)
|
78
|
+
end
|
79
|
+
|
80
|
+
# try out a replay message
|
81
|
+
requestor = make_requestor('localhost', 9090, MAIL_PROTOCOL)
|
82
|
+
result = requestor.request('replay', {})
|
83
|
+
puts("Replay Result: " + result)
|
84
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
2
|
+
# or more contributor license agreements. See the NOTICE file
|
3
|
+
# distributed with this work for additional information
|
4
|
+
# regarding copyright ownership. The ASF licenses this file
|
5
|
+
# to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance
|
7
|
+
# with the License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
require 'avro'
|
17
|
+
require 'webrick'
|
18
|
+
|
19
|
+
MAIL_PROTOCOL_JSON = <<-JSON
|
20
|
+
{"namespace": "example.proto",
|
21
|
+
"protocol": "Mail",
|
22
|
+
|
23
|
+
"types": [
|
24
|
+
{"name": "Message", "type": "record",
|
25
|
+
"fields": [
|
26
|
+
{"name": "to", "type": "string"},
|
27
|
+
{"name": "from", "type": "string"},
|
28
|
+
{"name": "body", "type": "string"}
|
29
|
+
]
|
30
|
+
}
|
31
|
+
],
|
32
|
+
|
33
|
+
"messages": {
|
34
|
+
"send": {
|
35
|
+
"request": [{"name": "message", "type": "Message"}],
|
36
|
+
"response": "string"
|
37
|
+
},
|
38
|
+
"replay": {
|
39
|
+
"request": [],
|
40
|
+
"response": "string"
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
JSON
|
45
|
+
|
46
|
+
MAIL_PROTOCOL = Avro::Protocol.parse(MAIL_PROTOCOL_JSON)
|
47
|
+
|
48
|
+
class MailResponder < Avro::IPC::Responder
|
49
|
+
def initialize
|
50
|
+
super(MAIL_PROTOCOL)
|
51
|
+
end
|
52
|
+
|
53
|
+
def call(message, request)
|
54
|
+
if message.name == 'send'
|
55
|
+
request_content = request['message']
|
56
|
+
"Sent message to #{request_content['to']} from #{request_content['from']} with body #{request_content['body']}"
|
57
|
+
elsif message.name == 'replay'
|
58
|
+
'replay'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class MailHandler < WEBrick::HTTPServlet::AbstractServlet
|
64
|
+
def do_POST(req, resp)
|
65
|
+
responder = MailResponder.new
|
66
|
+
call_request = Avro::IPC::FramedReader.new(StringIO.new(req.body)).read_framed_message
|
67
|
+
unframed_resp = responder.respond(call_request)
|
68
|
+
writer = Avro::IPC::FramedWriter.new(StringIO.new)
|
69
|
+
writer.write_framed_message(unframed_resp)
|
70
|
+
resp.body = writer.to_s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
if $0 == __FILE__
|
75
|
+
server = WEBrick::HTTPServer.new(:Host => 'localhost', :Port => 9090)
|
76
|
+
server.mount '/', MailHandler
|
77
|
+
trap("INT") { server.shutdown }
|
78
|
+
server.start
|
79
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'socket'
|
19
|
+
require 'avro'
|
20
|
+
|
21
|
+
MAIL_PROTOCOL_JSON = <<-EOS
|
22
|
+
{"namespace": "example.proto",
|
23
|
+
"protocol": "Mail",
|
24
|
+
|
25
|
+
"types": [
|
26
|
+
{"name": "Message", "type": "record",
|
27
|
+
"fields": [
|
28
|
+
{"name": "to", "type": "string"},
|
29
|
+
{"name": "from", "type": "string"},
|
30
|
+
{"name": "body", "type": "string"}
|
31
|
+
]
|
32
|
+
}
|
33
|
+
],
|
34
|
+
|
35
|
+
"messages": {
|
36
|
+
"send": {
|
37
|
+
"request": [{"name": "message", "type": "Message"}],
|
38
|
+
"response": "string"
|
39
|
+
},
|
40
|
+
"replay": {
|
41
|
+
"request": [],
|
42
|
+
"response": "string"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
EOS
|
47
|
+
|
48
|
+
MAIL_PROTOCOL = Avro::Protocol.parse(MAIL_PROTOCOL_JSON)
|
49
|
+
|
50
|
+
class MailResponder < Avro::IPC::Responder
|
51
|
+
def initialize
|
52
|
+
super(MAIL_PROTOCOL)
|
53
|
+
end
|
54
|
+
|
55
|
+
def call(message, request)
|
56
|
+
if message.name == 'send'
|
57
|
+
request_content = request['message']
|
58
|
+
"Sent message to #{request_content['to']} from #{request_content['from']} with body #{request_content['body']}"
|
59
|
+
elsif message.name == 'replay'
|
60
|
+
'replay'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class RequestHandler
|
66
|
+
def initialize(address, port)
|
67
|
+
@ip_address = address
|
68
|
+
@port = port
|
69
|
+
end
|
70
|
+
|
71
|
+
def run
|
72
|
+
server = TCPServer.new(@ip_address, @port)
|
73
|
+
while (session = server.accept)
|
74
|
+
handle(session)
|
75
|
+
session.close
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class MailHandler < RequestHandler
|
81
|
+
def handle(request)
|
82
|
+
responder = MailResponder.new()
|
83
|
+
transport = Avro::IPC::SocketTransport.new(request)
|
84
|
+
str = transport.read_framed_message
|
85
|
+
transport.write_framed_message(responder.respond(str))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if $0 == __FILE__
|
90
|
+
handler = MailHandler.new('localhost', 9090)
|
91
|
+
handler.run
|
92
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one
|
3
|
+
# or more contributor license agreements. See the NOTICE file
|
4
|
+
# distributed with this work for additional information
|
5
|
+
# regarding copyright ownership. The ASF licenses this file
|
6
|
+
# to you under the Apache License, Version 2.0 (the
|
7
|
+
# "License"); you may not use this file except in compliance
|
8
|
+
# with the License. You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
|
18
|
+
require 'test_help'
|
19
|
+
|
20
|
+
class TestDataFile < Test::Unit::TestCase
|
21
|
+
HERE = File.expand_path File.dirname(__FILE__)
|
22
|
+
def setup
|
23
|
+
if File.exists?(HERE + '/data.avr')
|
24
|
+
File.unlink(HERE + '/data.avr')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def teardown
|
29
|
+
if File.exists?(HERE + '/data.avr')
|
30
|
+
File.unlink(HERE + '/data.avr')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_differing_schemas_with_primitives
|
35
|
+
writer_schema = <<-JSON
|
36
|
+
{ "type": "record",
|
37
|
+
"name": "User",
|
38
|
+
"fields" : [
|
39
|
+
{"name": "username", "type": "string"},
|
40
|
+
{"name": "age", "type": "int"},
|
41
|
+
{"name": "verified", "type": "boolean", "default": "false"}
|
42
|
+
]}
|
43
|
+
JSON
|
44
|
+
|
45
|
+
data = [{"username" => "john", "age" => 25, "verified" => true},
|
46
|
+
{"username" => "ryan", "age" => 23, "verified" => false}]
|
47
|
+
|
48
|
+
Avro::DataFile.open('data.avr', 'w', writer_schema) do |dw|
|
49
|
+
data.each{|h| dw << h }
|
50
|
+
end
|
51
|
+
|
52
|
+
# extract the username only from the avro serialized file
|
53
|
+
reader_schema = <<-JSON
|
54
|
+
{ "type": "record",
|
55
|
+
"name": "User",
|
56
|
+
"fields" : [
|
57
|
+
{"name": "username", "type": "string"}
|
58
|
+
]}
|
59
|
+
JSON
|
60
|
+
|
61
|
+
Avro::DataFile.open('data.avr', 'r', reader_schema) do |dr|
|
62
|
+
dr.each_with_index do |record, i|
|
63
|
+
assert_equal data[i]['username'], record['username']
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_differing_schemas_with_complex_objects
|
69
|
+
writer_schema = <<-JSON
|
70
|
+
{ "type": "record",
|
71
|
+
"name": "something",
|
72
|
+
"fields": [
|
73
|
+
{"name": "something_fixed", "type": {"name": "inner_fixed",
|
74
|
+
"type": "fixed", "size": 3}},
|
75
|
+
{"name": "something_enum", "type": {"name": "inner_enum",
|
76
|
+
"type": "enum",
|
77
|
+
"symbols": ["hello", "goodbye"]}},
|
78
|
+
{"name": "something_array", "type": {"type": "array", "items": "int"}},
|
79
|
+
{"name": "something_map", "type": {"type": "map", "values": "int"}},
|
80
|
+
{"name": "something_record", "type": {"name": "inner_record",
|
81
|
+
"type": "record",
|
82
|
+
"fields": [
|
83
|
+
{"name": "inner", "type": "int"}
|
84
|
+
]}},
|
85
|
+
{"name": "username", "type": "string"}
|
86
|
+
]}
|
87
|
+
JSON
|
88
|
+
|
89
|
+
data = [{"username" => "john",
|
90
|
+
"something_fixed" => "foo",
|
91
|
+
"something_enum" => "hello",
|
92
|
+
"something_array" => [1,2,3],
|
93
|
+
"something_map" => {"a" => 1, "b" => 2},
|
94
|
+
"something_record" => {"inner" => 2},
|
95
|
+
"something_error" => {"code" => 403}
|
96
|
+
},
|
97
|
+
{"username" => "ryan",
|
98
|
+
"something_fixed" => "bar",
|
99
|
+
"something_enum" => "goodbye",
|
100
|
+
"something_array" => [1,2,3],
|
101
|
+
"something_map" => {"a" => 2, "b" => 6},
|
102
|
+
"something_record" => {"inner" => 1},
|
103
|
+
"something_error" => {"code" => 401}
|
104
|
+
}]
|
105
|
+
|
106
|
+
Avro::DataFile.open('data.avr', 'w', writer_schema) do |dw|
|
107
|
+
data.each{|d| dw << d }
|
108
|
+
end
|
109
|
+
|
110
|
+
%w[fixed enum record error array map union].each do |s|
|
111
|
+
reader = MultiJson.load(writer_schema)
|
112
|
+
reader['fields'] = reader['fields'].reject{|f| f['type']['type'] == s}
|
113
|
+
Avro::DataFile.open('data.avr', 'r', MultiJson.dump(reader)) do |dr|
|
114
|
+
dr.each_with_index do |obj, i|
|
115
|
+
reader['fields'].each do |field|
|
116
|
+
assert_equal data[i][field['name']], obj[field['name']]
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_data_writer_handles_sync_interval
|
124
|
+
writer_schema = <<-JSON
|
125
|
+
{ "type": "record",
|
126
|
+
"name": "something",
|
127
|
+
"fields": [
|
128
|
+
{"name": "something_boolean", "type": "boolean"}
|
129
|
+
]}
|
130
|
+
JSON
|
131
|
+
|
132
|
+
data = {"something_boolean" => true }
|
133
|
+
|
134
|
+
Avro::DataFile.open('data.avr', 'w', writer_schema) do |dw|
|
135
|
+
while dw.writer.tell < Avro::DataFile::SYNC_INTERVAL
|
136
|
+
dw << data
|
137
|
+
end
|
138
|
+
block_count = dw.block_count
|
139
|
+
dw << data
|
140
|
+
# ensure we didn't just write another block
|
141
|
+
assert_equal(block_count+1, dw.block_count)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_utf8
|
146
|
+
datafile = Avro::DataFile::open('data.avr', 'w', '"string"')
|
147
|
+
datafile << "家"
|
148
|
+
datafile.close
|
149
|
+
|
150
|
+
datafile = Avro::DataFile.open('data.avr')
|
151
|
+
datafile.each do |s|
|
152
|
+
assert_equal "家", s
|
153
|
+
end
|
154
|
+
datafile.close
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_deflate
|
158
|
+
Avro::DataFile.open('data.avr', 'w', '"string"', :deflate) do |writer|
|
159
|
+
writer << 'a' * 10_000
|
160
|
+
end
|
161
|
+
assert(File.size('data.avr') < 500)
|
162
|
+
|
163
|
+
records = []
|
164
|
+
Avro::DataFile.open('data.avr') do |reader|
|
165
|
+
reader.each {|record| records << record }
|
166
|
+
end
|
167
|
+
assert_equal records, ['a' * 10_000]
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_append_to_deflated_file
|
171
|
+
schema = Avro::Schema.parse('"string"')
|
172
|
+
writer = Avro::IO::DatumWriter.new(schema)
|
173
|
+
file = Avro::DataFile::Writer.new(File.open('data.avr', 'wb'), writer, schema, :deflate)
|
174
|
+
file << 'a' * 10_000
|
175
|
+
file.close
|
176
|
+
|
177
|
+
file = Avro::DataFile::Writer.new(File.open('data.avr', 'a+b'), writer)
|
178
|
+
file << 'b' * 10_000
|
179
|
+
file.close
|
180
|
+
assert(File.size('data.avr') < 1_000)
|
181
|
+
|
182
|
+
records = []
|
183
|
+
Avro::DataFile.open('data.avr') do |reader|
|
184
|
+
reader.each {|record| records << record }
|
185
|
+
end
|
186
|
+
assert_equal records, ['a' * 10_000, 'b' * 10_000]
|
187
|
+
end
|
188
|
+
end
|