avro-jruby 1.7.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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