avro 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/Manifest +19 -0
- data/Rakefile +59 -0
- data/avro.gemspec +34 -0
- data/interop/test_interop.rb +41 -0
- data/lib/avro.rb +39 -0
- data/lib/avro/collect_hash.rb +25 -0
- data/lib/avro/data_file.rb +243 -0
- data/lib/avro/io.rb +572 -0
- data/lib/avro/ipc.rb +443 -0
- data/lib/avro/protocol.rb +160 -0
- data/lib/avro/schema.rb +431 -0
- data/test/random_data.rb +90 -0
- data/test/sample_ipc_client.rb +86 -0
- data/test/sample_ipc_server.rb +91 -0
- data/test/test_help.rb +23 -0
- data/test/test_io.rb +361 -0
- data/test/test_protocol.rb +192 -0
- data/tmp/test.rb.avro +0 -0
- metadata +94 -0
@@ -0,0 +1,86 @@
|
|
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].to_i
|
70
|
+
num_message = 1 if num_messages == 0
|
71
|
+
|
72
|
+
# build the parameters for the request
|
73
|
+
params = {'message' => message}
|
74
|
+
|
75
|
+
# send the requests and print the result
|
76
|
+
num_messages.times do
|
77
|
+
requestor = make_requestor('localhost', 9090, MAIL_PROTOCOL)
|
78
|
+
result = requestor.request('send', params)
|
79
|
+
puts("Result: " + result)
|
80
|
+
end
|
81
|
+
|
82
|
+
# try out a replay message
|
83
|
+
requestor = make_requestor('localhost', 9090, MAIL_PROTOCOL)
|
84
|
+
result = requestor.request('replay', {})
|
85
|
+
puts("Replay Result: " + result)
|
86
|
+
end
|
@@ -0,0 +1,91 @@
|
|
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
|
+
transport.write_framed_message(responder.respond(transport))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if $0 == __FILE__
|
89
|
+
handler = MailHandler.new('localhost', 9090)
|
90
|
+
handler.run
|
91
|
+
end
|
data/test/test_help.rb
ADDED
@@ -0,0 +1,23 @@
|
|
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
|
+
|
17
|
+
require 'rubygems'
|
18
|
+
require 'test/unit'
|
19
|
+
require 'stringio'
|
20
|
+
require 'fileutils'
|
21
|
+
FileUtils.mkdir_p('tmp')
|
22
|
+
require 'avro'
|
23
|
+
require 'random_data'
|
data/test/test_io.rb
ADDED
@@ -0,0 +1,361 @@
|
|
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
|
+
|
17
|
+
require 'test_help'
|
18
|
+
|
19
|
+
class TestIO < Test::Unit::TestCase
|
20
|
+
DATAFILE = 'tmp/test.rb.avro'
|
21
|
+
Schema = Avro::Schema
|
22
|
+
|
23
|
+
def test_null
|
24
|
+
check_default('"null"', "null", nil)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_boolean
|
28
|
+
check_default('"boolean"', "true", true)
|
29
|
+
check_default('"boolean"', "false", false)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_string
|
33
|
+
check_default('"string"', '"foo"', "foo")
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_bytes
|
37
|
+
check_default('"bytes"', '"foo"', "foo")
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_int
|
41
|
+
check_default('"int"', "5", 5)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_long
|
45
|
+
check_default('"long"', "9", 9)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_float
|
49
|
+
check_default('"float"', "1.2", 1.2)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_double
|
53
|
+
check_default('"double"', "1.2", 1.2)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_array
|
57
|
+
array_schema = '{"type": "array", "items": "long"}'
|
58
|
+
check_default(array_schema, "[1]", [1])
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_map
|
62
|
+
map_schema = '{"type": "map", "values": "long"}'
|
63
|
+
check_default(map_schema, '{"a": 1}', {"a" => 1})
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_record
|
67
|
+
record_schema = <<EOS
|
68
|
+
{"type": "record",
|
69
|
+
"name": "Test",
|
70
|
+
"fields": [{"name": "f",
|
71
|
+
"type": "long"}]}
|
72
|
+
EOS
|
73
|
+
check_default(record_schema, '{"f": 11}', {"f" => 11})
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_enum
|
77
|
+
enum_schema = '{"type": "enum", "name": "Test","symbols": ["A", "B"]}'
|
78
|
+
check_default(enum_schema, '"B"', "B")
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_recursive
|
82
|
+
recursive_schema = <<EOS
|
83
|
+
{"type": "record",
|
84
|
+
"name": "Node",
|
85
|
+
"fields": [{"name": "label", "type": "string"},
|
86
|
+
{"name": "children",
|
87
|
+
"type": {"type": "array", "items": "Node"}}]}
|
88
|
+
EOS
|
89
|
+
check(recursive_schema)
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_union
|
93
|
+
union_schema = <<EOS
|
94
|
+
["string",
|
95
|
+
"null",
|
96
|
+
"long",
|
97
|
+
{"type": "record",
|
98
|
+
"name": "Cons",
|
99
|
+
"fields": [{"name": "car", "type": "string"},
|
100
|
+
{"name": "cdr", "type": "string"}]}]
|
101
|
+
EOS
|
102
|
+
check(union_schema)
|
103
|
+
check_default('["double", "long"]', "1.1", 1.1)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_lisp
|
107
|
+
lisp_schema = <<EOS
|
108
|
+
{"type": "record",
|
109
|
+
"name": "Lisp",
|
110
|
+
"fields": [{"name": "value",
|
111
|
+
"type": ["null", "string",
|
112
|
+
{"type": "record",
|
113
|
+
"name": "Cons",
|
114
|
+
"fields": [{"name": "car", "type": "Lisp"},
|
115
|
+
{"name": "cdr", "type": "Lisp"}]}]}]}
|
116
|
+
EOS
|
117
|
+
check(lisp_schema)
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_fixed
|
121
|
+
fixed_schema = '{"type": "fixed", "name": "Test", "size": 1}'
|
122
|
+
check_default(fixed_schema, '"a"', "a")
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_enum_with_duplicate
|
126
|
+
str = '{"type": "enum", "name": "Test","symbols" : ["AA", "AA"]}'
|
127
|
+
assert_raises(Avro::SchemaParseError) do
|
128
|
+
schema = Avro::Schema.parse str
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
BINARY_INT_ENCODINGS = [
|
133
|
+
[0, '00'],
|
134
|
+
[-1, '01'],
|
135
|
+
[1, '02'],
|
136
|
+
[-2, '03'],
|
137
|
+
[2, '04'],
|
138
|
+
[-64, '7f'],
|
139
|
+
[64, '80 01'],
|
140
|
+
[8192, '80 80 01'],
|
141
|
+
[-8193, '81 80 01'],
|
142
|
+
]
|
143
|
+
|
144
|
+
def avro_hexlify(reader)
|
145
|
+
bytes = []
|
146
|
+
current_byte = reader.read(1)
|
147
|
+
bytes << hexlify(current_byte)
|
148
|
+
while (current_byte[0] & 0x80) != 0
|
149
|
+
current_byte = reader.read(1)
|
150
|
+
bytes << hexlify(current_byte)
|
151
|
+
end
|
152
|
+
bytes.join ' '
|
153
|
+
end
|
154
|
+
|
155
|
+
def hexlify(msg)
|
156
|
+
msg.split("").collect { |c| c[0].to_s(16).rjust(2, '0') }.join
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_binary_int_encoding
|
160
|
+
for value, hex_encoding in BINARY_INT_ENCODINGS
|
161
|
+
# write datum in binary to string buffer
|
162
|
+
buffer = StringIO.new
|
163
|
+
encoder = Avro::IO::BinaryEncoder.new(buffer)
|
164
|
+
datum_writer = Avro::IO::DatumWriter.new(Avro::Schema.parse('"int"'))
|
165
|
+
datum_writer.write(value, encoder)
|
166
|
+
|
167
|
+
buffer.seek(0)
|
168
|
+
hex_val = avro_hexlify(buffer)
|
169
|
+
|
170
|
+
assert_equal hex_encoding, hex_val
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_binary_long_encoding
|
175
|
+
for value, hex_encoding in BINARY_INT_ENCODINGS
|
176
|
+
buffer = StringIO.new
|
177
|
+
encoder = Avro::IO::BinaryEncoder.new(buffer)
|
178
|
+
datum_writer = Avro::IO::DatumWriter.new(Avro::Schema.parse('"long"'))
|
179
|
+
datum_writer.write(value, encoder)
|
180
|
+
|
181
|
+
# read it out of the buffer and hexlify it
|
182
|
+
buffer.seek(0)
|
183
|
+
hex_val = avro_hexlify(buffer)
|
184
|
+
|
185
|
+
assert_equal hex_encoding, hex_val
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_skip_long
|
190
|
+
for value_to_skip, hex_encoding in BINARY_INT_ENCODINGS
|
191
|
+
value_to_read = 6253
|
192
|
+
|
193
|
+
# write some data in binary to string buffer
|
194
|
+
writer = StringIO.new
|
195
|
+
encoder = Avro::IO::BinaryEncoder.new(writer)
|
196
|
+
datum_writer = Avro::IO::DatumWriter.new(Avro::Schema.parse('"long"'))
|
197
|
+
datum_writer.write(value_to_skip, encoder)
|
198
|
+
datum_writer.write(value_to_read, encoder)
|
199
|
+
|
200
|
+
# skip the value
|
201
|
+
reader = StringIO.new(writer.string())
|
202
|
+
decoder = Avro::IO::BinaryDecoder.new(reader)
|
203
|
+
decoder.skip_long()
|
204
|
+
|
205
|
+
# read data from string buffer
|
206
|
+
datum_reader = Avro::IO::DatumReader.new(Avro::Schema.parse('"long"'))
|
207
|
+
read_value = datum_reader.read(decoder)
|
208
|
+
|
209
|
+
# check it
|
210
|
+
assert_equal value_to_read, read_value
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_skip_int
|
215
|
+
for value_to_skip, hex_encoding in BINARY_INT_ENCODINGS
|
216
|
+
value_to_read = 6253
|
217
|
+
|
218
|
+
writer = StringIO.new
|
219
|
+
encoder = Avro::IO::BinaryEncoder.new(writer)
|
220
|
+
datum_writer = Avro::IO::DatumWriter.new(Avro::Schema.parse('"int"'))
|
221
|
+
datum_writer.write(value_to_skip, encoder)
|
222
|
+
datum_writer.write(value_to_read, encoder)
|
223
|
+
|
224
|
+
reader = StringIO.new(writer.string)
|
225
|
+
decoder = Avro::IO::BinaryDecoder.new(reader)
|
226
|
+
decoder.skip_int
|
227
|
+
|
228
|
+
datum_reader = Avro::IO::DatumReader.new(Avro::Schema.parse('"int"'))
|
229
|
+
read_value = datum_reader.read(decoder)
|
230
|
+
|
231
|
+
assert_equal value_to_read, read_value
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_schema_promotion
|
236
|
+
promotable_schemas = ['"int"', '"long"', '"float"', '"double"']
|
237
|
+
incorrect = 0
|
238
|
+
promotable_schemas.each_with_index do |ws, i|
|
239
|
+
writers_schema = Avro::Schema.parse(ws)
|
240
|
+
datum_to_write = 219
|
241
|
+
for rs in promotable_schemas[(i + 1)..-1]
|
242
|
+
readers_schema = Avro::Schema.parse(rs)
|
243
|
+
writer, enc, dw = write_datum(datum_to_write, writers_schema)
|
244
|
+
datum_read = read_datum(writer, writers_schema, readers_schema)
|
245
|
+
if datum_read != datum_to_write
|
246
|
+
incorrect += 1
|
247
|
+
end
|
248
|
+
end
|
249
|
+
assert_equal(incorrect, 0)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
private
|
253
|
+
|
254
|
+
def check_default(schema_json, default_json, default_value)
|
255
|
+
check(schema_json)
|
256
|
+
actual_schema = '{"type": "record", "name": "Foo", "fields": []}'
|
257
|
+
actual = Avro::Schema.parse(actual_schema)
|
258
|
+
|
259
|
+
expected_schema = <<EOS
|
260
|
+
{"type": "record",
|
261
|
+
"name": "Foo",
|
262
|
+
"fields": [{"name": "f", "type": #{schema_json}, "default": #{default_json}}]}
|
263
|
+
EOS
|
264
|
+
expected = Avro::Schema.parse(expected_schema)
|
265
|
+
|
266
|
+
reader = Avro::IO::DatumReader.new(actual, expected)
|
267
|
+
record = reader.read(Avro::IO::BinaryDecoder.new(StringIO.new))
|
268
|
+
assert_equal default_value, record["f"]
|
269
|
+
end
|
270
|
+
|
271
|
+
def check(str)
|
272
|
+
# parse schema, then convert back to string
|
273
|
+
schema = Avro::Schema.parse str
|
274
|
+
|
275
|
+
parsed_string = schema.to_s
|
276
|
+
|
277
|
+
# test that the round-trip didn't mess up anything
|
278
|
+
# NB: I don't think we should do this. Why enforce ordering?
|
279
|
+
assert_equal(Yajl.load(str),
|
280
|
+
Yajl.load(parsed_string))
|
281
|
+
|
282
|
+
# test __eq__
|
283
|
+
assert_equal(schema, Avro::Schema.parse(str))
|
284
|
+
|
285
|
+
# test hashcode doesn't generate infinite recursion
|
286
|
+
schema.hash
|
287
|
+
|
288
|
+
# test serialization of random data
|
289
|
+
randomdata = RandomData.new(schema)
|
290
|
+
9.times { checkser(schema, randomdata) }
|
291
|
+
|
292
|
+
# test writing of data to file
|
293
|
+
check_datafile(schema)
|
294
|
+
end
|
295
|
+
|
296
|
+
def checkser(schm, randomdata)
|
297
|
+
datum = randomdata.next
|
298
|
+
assert validate(schm, datum)
|
299
|
+
w = Avro::IO::DatumWriter.new(schm)
|
300
|
+
writer = StringIO.new "", "w"
|
301
|
+
w.write(datum, Avro::IO::BinaryEncoder.new(writer))
|
302
|
+
r = datum_reader(schm)
|
303
|
+
reader = StringIO.new(writer.string)
|
304
|
+
ob = r.read(Avro::IO::BinaryDecoder.new(reader))
|
305
|
+
assert_equal(datum, ob) # FIXME check on assertdata conditional
|
306
|
+
end
|
307
|
+
|
308
|
+
def check_datafile(schm)
|
309
|
+
seed = 0
|
310
|
+
count = 10
|
311
|
+
random_data = RandomData.new(schm, seed)
|
312
|
+
|
313
|
+
|
314
|
+
f = File.open(DATAFILE, 'wb')
|
315
|
+
dw = Avro::DataFile::Writer.new(f, datum_writer(schm), schm)
|
316
|
+
count.times{ dw << random_data.next }
|
317
|
+
dw.close
|
318
|
+
|
319
|
+
random_data = RandomData.new(schm, seed)
|
320
|
+
|
321
|
+
|
322
|
+
f = File.open(DATAFILE, 'r+')
|
323
|
+
dr = Avro::DataFile::Reader.new(f, datum_reader(schm))
|
324
|
+
|
325
|
+
last_index = nil
|
326
|
+
dr.each_with_index do |data, c|
|
327
|
+
last_index = c
|
328
|
+
# FIXME assertdata conditional
|
329
|
+
assert_equal(random_data.next, data)
|
330
|
+
end
|
331
|
+
dr.close
|
332
|
+
assert_equal count, last_index+1
|
333
|
+
end
|
334
|
+
|
335
|
+
def validate(schm, datum)
|
336
|
+
Avro::Schema.validate(schm, datum)
|
337
|
+
end
|
338
|
+
|
339
|
+
def datum_writer(schm)
|
340
|
+
Avro::IO::DatumWriter.new(schm)
|
341
|
+
end
|
342
|
+
|
343
|
+
def datum_reader(schm)
|
344
|
+
Avro::IO::DatumReader.new(schm)
|
345
|
+
end
|
346
|
+
|
347
|
+
def write_datum(datum, writers_schema)
|
348
|
+
writer = StringIO.new
|
349
|
+
encoder = Avro::IO::BinaryEncoder.new(writer)
|
350
|
+
datum_writer = Avro::IO::DatumWriter.new(writers_schema)
|
351
|
+
datum_writer.write(datum, encoder)
|
352
|
+
[writer, encoder, datum_writer]
|
353
|
+
end
|
354
|
+
|
355
|
+
def read_datum(buffer, writers_schema, readers_schema=nil)
|
356
|
+
reader = StringIO.new(buffer.string)
|
357
|
+
decoder = Avro::IO::BinaryDecoder.new(reader)
|
358
|
+
datum_reader = Avro::IO::DatumReader.new(writers_schema, readers_schema)
|
359
|
+
datum_reader.read(decoder)
|
360
|
+
end
|
361
|
+
end
|