avro-salsify-fork 1.9.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,111 @@
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 TestLogicalTypes < Test::Unit::TestCase
21
+ def test_int_date
22
+ schema = Avro::Schema.parse <<-SCHEMA
23
+ { "type": "int", "logicalType": "date" }
24
+ SCHEMA
25
+
26
+ assert_equal 'date', schema.logical_type
27
+ assert_encode_and_decode Date.today, schema
28
+ end
29
+
30
+ def test_int_date_conversion
31
+ type = Avro::LogicalTypes::IntDate
32
+
33
+ assert_equal 5, type.encode(Date.new(1970, 1, 6))
34
+ assert_equal 0, type.encode(Date.new(1970, 1, 1))
35
+ assert_equal -5, type.encode(Date.new(1969, 12, 27))
36
+
37
+ assert_equal Date.new(1970, 1, 6), type.decode(5)
38
+ assert_equal Date.new(1970, 1, 1), type.decode(0)
39
+ assert_equal Date.new(1969, 12, 27), type.decode(-5)
40
+ end
41
+
42
+ def test_timestamp_millis_long
43
+ schema = Avro::Schema.parse <<-SCHEMA
44
+ { "type": "long", "logicalType": "timestamp-millis" }
45
+ SCHEMA
46
+
47
+ # The Time.at format is (seconds, microseconds) since Epoch.
48
+ datum = Time.at(628232400, 12000)
49
+
50
+ assert_equal 'timestamp-millis', schema.logical_type
51
+ assert_encode_and_decode datum, schema
52
+ end
53
+
54
+ def test_timestamp_millis_long_conversion
55
+ type = Avro::LogicalTypes::TimestampMillis
56
+
57
+ now = Time.now.utc
58
+ now_millis = Time.utc(now.year, now.month, now.day, now.hour, now.min, now.sec, now.usec / 1000 * 1000)
59
+
60
+ assert_equal now_millis, type.decode(type.encode(now_millis))
61
+ assert_equal 1432849613221, type.encode(Time.utc(2015, 5, 28, 21, 46, 53, 221000))
62
+ assert_equal 1432849613221, type.encode(DateTime.new(2015, 5, 28, 21, 46, 53.221))
63
+ assert_equal Time.utc(2015, 5, 28, 21, 46, 53, 221000), type.decode(1432849613221)
64
+ end
65
+
66
+ def test_timestamp_micros_long
67
+ schema = Avro::Schema.parse <<-SCHEMA
68
+ { "type": "long", "logicalType": "timestamp-micros" }
69
+ SCHEMA
70
+
71
+ # The Time.at format is (seconds, microseconds) since Epoch.
72
+ datum = Time.at(628232400, 12345)
73
+
74
+ assert_equal 'timestamp-micros', schema.logical_type
75
+ assert_encode_and_decode datum, schema
76
+ end
77
+
78
+ def test_timestamp_micros_long_conversion
79
+ type = Avro::LogicalTypes::TimestampMicros
80
+
81
+ now = Time.now.utc
82
+
83
+ assert_equal now, type.decode(type.encode(now))
84
+ assert_equal 1432849613221843, type.encode(Time.utc(2015, 5, 28, 21, 46, 53, 221843))
85
+ assert_equal 1432849613221843, type.encode(DateTime.new(2015, 5, 28, 21, 46, 53.221843))
86
+ assert_equal Time.utc(2015, 5, 28, 21, 46, 53, 221843), type.decode(1432849613221843)
87
+ end
88
+
89
+ def encode(datum, schema)
90
+ buffer = StringIO.new("")
91
+ encoder = Avro::IO::BinaryEncoder.new(buffer)
92
+
93
+ datum_writer = Avro::IO::DatumWriter.new(schema)
94
+ datum_writer.write(datum, encoder)
95
+
96
+ buffer.string
97
+ end
98
+
99
+ def decode(encoded, schema)
100
+ buffer = StringIO.new(encoded)
101
+ decoder = Avro::IO::BinaryDecoder.new(buffer)
102
+
103
+ datum_reader = Avro::IO::DatumReader.new(schema, schema)
104
+ datum_reader.read(decoder)
105
+ end
106
+
107
+ def assert_encode_and_decode(datum, schema)
108
+ encoded = encode(datum, schema)
109
+ assert_equal datum, decode(encoded, schema)
110
+ end
111
+ end
@@ -0,0 +1,199 @@
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 TestProtocol < Test::Unit::TestCase
20
+
21
+ class ExampleProtocol
22
+ attr_reader :protocol_string, :valid, :name
23
+ attr_accessor :comment
24
+ def initialize(protocol_string, name=nil, comment='')
25
+ @protocol_string = protocol_string
26
+ @name = name || protocol_string # default to schema_string for name
27
+ @comment = comment
28
+ end
29
+ end
30
+ #
31
+ # Example Protocols
32
+ #
33
+
34
+ EXAMPLES = [
35
+ ExampleProtocol.new(<<-EOS, true),
36
+ {
37
+ "namespace": "com.acme",
38
+ "protocol": "HelloWorld",
39
+
40
+ "types": [
41
+ {"name": "Greeting", "type": "record", "fields": [
42
+ {"name": "message", "type": "string"}]},
43
+ {"name": "Curse", "type": "error", "fields": [
44
+ {"name": "message", "type": "string"}]}
45
+ ],
46
+
47
+ "messages": {
48
+ "hello": {
49
+ "request": [{"name": "greeting", "type": "Greeting" }],
50
+ "response": "Greeting",
51
+ "errors": ["Curse"]
52
+ }
53
+ }
54
+ }
55
+ EOS
56
+
57
+ ExampleProtocol.new(<<-EOS, true),
58
+ {"namespace": "org.apache.avro.test",
59
+ "protocol": "Simple",
60
+
61
+ "types": [
62
+ {"name": "Kind", "type": "enum", "symbols": ["FOO","BAR","BAZ"]},
63
+
64
+ {"name": "MD5", "type": "fixed", "size": 16},
65
+
66
+ {"name": "TestRecord", "type": "record",
67
+ "fields": [
68
+ {"name": "name", "type": "string", "order": "ignore"},
69
+ {"name": "kind", "type": "Kind", "order": "descending"},
70
+ {"name": "hash", "type": "MD5"}
71
+ ]
72
+ },
73
+
74
+ {"name": "TestError", "type": "error", "fields": [
75
+ {"name": "message", "type": "string"}
76
+ ]
77
+ }
78
+
79
+ ],
80
+
81
+ "messages": {
82
+
83
+ "hello": {
84
+ "request": [{"name": "greeting", "type": "string"}],
85
+ "response": "string"
86
+ },
87
+
88
+ "echo": {
89
+ "request": [{"name": "record", "type": "TestRecord"}],
90
+ "response": "TestRecord"
91
+ },
92
+
93
+ "add": {
94
+ "request": [{"name": "arg1", "type": "int"}, {"name": "arg2", "type": "int"}],
95
+ "response": "int"
96
+ },
97
+
98
+ "echoBytes": {
99
+ "request": [{"name": "data", "type": "bytes"}],
100
+ "response": "bytes"
101
+ },
102
+
103
+ "error": {
104
+ "request": [],
105
+ "response": "null",
106
+ "errors": ["TestError"]
107
+ }
108
+ }
109
+
110
+ }
111
+ EOS
112
+ ExampleProtocol.new(<<-EOS, true),
113
+ {"namespace": "org.apache.avro.test.namespace",
114
+ "protocol": "TestNamespace",
115
+
116
+ "types": [
117
+ {"name": "org.apache.avro.test.util.MD5", "type": "fixed", "size": 16},
118
+ {"name": "TestRecord", "type": "record",
119
+ "fields": [ {"name": "hash", "type": "org.apache.avro.test.util.MD5"} ]
120
+ },
121
+ {"name": "TestError", "namespace": "org.apache.avro.test.errors",
122
+ "type": "error", "fields": [ {"name": "message", "type": "string"} ]
123
+ }
124
+ ],
125
+
126
+ "messages": {
127
+ "echo": {
128
+ "request": [{"name": "record", "type": "TestRecord"}],
129
+ "response": "TestRecord"
130
+ },
131
+
132
+ "error": {
133
+ "request": [],
134
+ "response": "null",
135
+ "errors": ["org.apache.avro.test.errors.TestError"]
136
+ }
137
+
138
+ }
139
+
140
+ }
141
+ EOS
142
+ ExampleProtocol.new(<<-EOS, true)
143
+ {"namespace": "org.apache.avro.test",
144
+ "protocol": "BulkData",
145
+
146
+ "types": [],
147
+
148
+ "messages": {
149
+
150
+ "read": {
151
+ "request": [],
152
+ "response": "bytes"
153
+ },
154
+
155
+ "write": {
156
+ "request": [ {"name": "data", "type": "bytes"} ],
157
+ "response": "null"
158
+ }
159
+
160
+ }
161
+
162
+ }
163
+ EOS
164
+ ]
165
+
166
+ Protocol = Avro::Protocol
167
+ def test_parse
168
+ EXAMPLES.each do |example|
169
+ assert_nothing_raised("should be valid: #{example.protocol_string}") {
170
+ Protocol.parse(example.protocol_string)
171
+ }
172
+ end
173
+ end
174
+
175
+ def test_valid_cast_to_string_after_parse
176
+ EXAMPLES.each do |example|
177
+ assert_nothing_raised("round tripped okay #{example.protocol_string}") {
178
+ foo = Protocol.parse(example.protocol_string).to_s
179
+ Protocol.parse(foo)
180
+ }
181
+ end
182
+ end
183
+
184
+ def test_equivalence_after_round_trip
185
+ EXAMPLES.each do |example|
186
+ original = Protocol.parse(example.protocol_string)
187
+ round_trip = Protocol.parse(original.to_s)
188
+
189
+ assert_equal original, round_trip
190
+ end
191
+ end
192
+
193
+ def test_namespaces
194
+ protocol = Protocol.parse(EXAMPLES.first.protocol_string)
195
+ protocol.types.each do |type|
196
+ assert_equal type.namespace, 'com.acme'
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,146 @@
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 TestSchema < Test::Unit::TestCase
20
+ def test_default_namespace
21
+ schema = Avro::Schema.parse <<-SCHEMA
22
+ {"type": "record", "name": "OuterRecord", "fields": [
23
+ {"name": "field1", "type": {
24
+ "type": "record", "name": "InnerRecord", "fields": []
25
+ }},
26
+ {"name": "field2", "type": "InnerRecord"}
27
+ ]}
28
+ SCHEMA
29
+
30
+ assert_equal schema.name, 'OuterRecord'
31
+ assert_equal schema.fullname, 'OuterRecord'
32
+ assert_nil schema.namespace
33
+
34
+ schema.fields.each do |field|
35
+ assert_equal field.type.name, 'InnerRecord'
36
+ assert_equal field.type.fullname, 'InnerRecord'
37
+ assert_nil field.type.namespace
38
+ end
39
+ end
40
+
41
+ def test_inherited_namespace
42
+ schema = Avro::Schema.parse <<-SCHEMA
43
+ {"type": "record", "name": "OuterRecord", "namespace": "my.name.space",
44
+ "fields": [
45
+ {"name": "definition", "type": {
46
+ "type": "record", "name": "InnerRecord", "fields": []
47
+ }},
48
+ {"name": "relativeReference", "type": "InnerRecord"},
49
+ {"name": "absoluteReference", "type": "my.name.space.InnerRecord"}
50
+ ]}
51
+ SCHEMA
52
+
53
+ assert_equal schema.name, 'OuterRecord'
54
+ assert_equal schema.fullname, 'my.name.space.OuterRecord'
55
+ assert_equal schema.namespace, 'my.name.space'
56
+ schema.fields.each do |field|
57
+ assert_equal field.type.name, 'InnerRecord'
58
+ assert_equal field.type.fullname, 'my.name.space.InnerRecord'
59
+ assert_equal field.type.namespace, 'my.name.space'
60
+ end
61
+ end
62
+
63
+ def test_inherited_namespace_from_dotted_name
64
+ schema = Avro::Schema.parse <<-SCHEMA
65
+ {"type": "record", "name": "my.name.space.OuterRecord", "fields": [
66
+ {"name": "definition", "type": {
67
+ "type": "enum", "name": "InnerEnum", "symbols": ["HELLO", "WORLD"]
68
+ }},
69
+ {"name": "relativeReference", "type": "InnerEnum"},
70
+ {"name": "absoluteReference", "type": "my.name.space.InnerEnum"}
71
+ ]}
72
+ SCHEMA
73
+
74
+ assert_equal schema.name, 'OuterRecord'
75
+ assert_equal schema.fullname, 'my.name.space.OuterRecord'
76
+ assert_equal schema.namespace, 'my.name.space'
77
+ schema.fields.each do |field|
78
+ assert_equal field.type.name, 'InnerEnum'
79
+ assert_equal field.type.fullname, 'my.name.space.InnerEnum'
80
+ assert_equal field.type.namespace, 'my.name.space'
81
+ end
82
+ end
83
+
84
+ def test_nested_namespaces
85
+ schema = Avro::Schema.parse <<-SCHEMA
86
+ {"type": "record", "name": "outer.OuterRecord", "fields": [
87
+ {"name": "middle", "type": {
88
+ "type": "record", "name": "middle.MiddleRecord", "fields": [
89
+ {"name": "inner", "type": {
90
+ "type": "record", "name": "InnerRecord", "fields": [
91
+ {"name": "recursive", "type": "MiddleRecord"}
92
+ ]
93
+ }}
94
+ ]
95
+ }}
96
+ ]}
97
+ SCHEMA
98
+
99
+ assert_equal schema.name, 'OuterRecord'
100
+ assert_equal schema.fullname, 'outer.OuterRecord'
101
+ assert_equal schema.namespace, 'outer'
102
+ middle = schema.fields.first.type
103
+ assert_equal middle.name, 'MiddleRecord'
104
+ assert_equal middle.fullname, 'middle.MiddleRecord'
105
+ assert_equal middle.namespace, 'middle'
106
+ inner = middle.fields.first.type
107
+ assert_equal inner.name, 'InnerRecord'
108
+ assert_equal inner.fullname, 'middle.InnerRecord'
109
+ assert_equal inner.namespace, 'middle'
110
+ assert_equal inner.fields.first.type, middle
111
+ end
112
+
113
+ def test_to_avro_includes_namespaces
114
+ schema = Avro::Schema.parse <<-SCHEMA
115
+ {"type": "record", "name": "my.name.space.OuterRecord", "fields": [
116
+ {"name": "definition", "type": {
117
+ "type": "fixed", "name": "InnerFixed", "size": 16
118
+ }},
119
+ {"name": "reference", "type": "InnerFixed"}
120
+ ]}
121
+ SCHEMA
122
+
123
+ assert_equal schema.to_avro, {
124
+ 'type' => 'record', 'name' => 'OuterRecord', 'namespace' => 'my.name.space',
125
+ 'fields' => [
126
+ {'name' => 'definition', 'type' => {
127
+ 'type' => 'fixed', 'name' => 'InnerFixed', 'namespace' => 'my.name.space',
128
+ 'size' => 16
129
+ }},
130
+ {'name' => 'reference', 'type' => 'my.name.space.InnerFixed'}
131
+ ]
132
+ }
133
+ end
134
+
135
+ def test_unknown_named_type
136
+ error = assert_raise Avro::UnknownSchemaError do
137
+ Avro::Schema.parse <<-SCHEMA
138
+ {"type": "record", "name": "my.name.space.Record", "fields": [
139
+ {"name": "reference", "type": "MissingType"}
140
+ ]}
141
+ SCHEMA
142
+ end
143
+
144
+ assert_equal '"MissingType" is not a schema we know about.', error.message
145
+ end
146
+ end