deimos-temp-fork 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +83 -0
  3. data/.gitignore +41 -0
  4. data/.gitmodules +0 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +333 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +349 -0
  10. data/CODE_OF_CONDUCT.md +77 -0
  11. data/Dockerfile +23 -0
  12. data/Gemfile +6 -0
  13. data/Gemfile.lock +286 -0
  14. data/Guardfile +22 -0
  15. data/LICENSE.md +195 -0
  16. data/README.md +1099 -0
  17. data/Rakefile +13 -0
  18. data/bin/deimos +4 -0
  19. data/deimos-ruby.gemspec +44 -0
  20. data/docker-compose.yml +71 -0
  21. data/docs/ARCHITECTURE.md +140 -0
  22. data/docs/CONFIGURATION.md +236 -0
  23. data/docs/DATABASE_BACKEND.md +147 -0
  24. data/docs/INTEGRATION_TESTS.md +52 -0
  25. data/docs/PULL_REQUEST_TEMPLATE.md +35 -0
  26. data/docs/UPGRADING.md +128 -0
  27. data/lib/deimos-temp-fork.rb +95 -0
  28. data/lib/deimos/active_record_consume/batch_consumption.rb +164 -0
  29. data/lib/deimos/active_record_consume/batch_slicer.rb +27 -0
  30. data/lib/deimos/active_record_consume/message_consumption.rb +79 -0
  31. data/lib/deimos/active_record_consume/schema_model_converter.rb +52 -0
  32. data/lib/deimos/active_record_consumer.rb +67 -0
  33. data/lib/deimos/active_record_producer.rb +87 -0
  34. data/lib/deimos/backends/base.rb +32 -0
  35. data/lib/deimos/backends/db.rb +41 -0
  36. data/lib/deimos/backends/kafka.rb +33 -0
  37. data/lib/deimos/backends/kafka_async.rb +33 -0
  38. data/lib/deimos/backends/test.rb +20 -0
  39. data/lib/deimos/batch_consumer.rb +7 -0
  40. data/lib/deimos/config/configuration.rb +381 -0
  41. data/lib/deimos/config/phobos_config.rb +137 -0
  42. data/lib/deimos/consume/batch_consumption.rb +150 -0
  43. data/lib/deimos/consume/message_consumption.rb +94 -0
  44. data/lib/deimos/consumer.rb +104 -0
  45. data/lib/deimos/instrumentation.rb +76 -0
  46. data/lib/deimos/kafka_message.rb +60 -0
  47. data/lib/deimos/kafka_source.rb +128 -0
  48. data/lib/deimos/kafka_topic_info.rb +102 -0
  49. data/lib/deimos/message.rb +79 -0
  50. data/lib/deimos/metrics/datadog.rb +47 -0
  51. data/lib/deimos/metrics/mock.rb +39 -0
  52. data/lib/deimos/metrics/provider.rb +36 -0
  53. data/lib/deimos/monkey_patches/phobos_cli.rb +35 -0
  54. data/lib/deimos/monkey_patches/phobos_producer.rb +51 -0
  55. data/lib/deimos/poll_info.rb +9 -0
  56. data/lib/deimos/producer.rb +224 -0
  57. data/lib/deimos/railtie.rb +8 -0
  58. data/lib/deimos/schema_backends/avro_base.rb +140 -0
  59. data/lib/deimos/schema_backends/avro_local.rb +30 -0
  60. data/lib/deimos/schema_backends/avro_schema_coercer.rb +119 -0
  61. data/lib/deimos/schema_backends/avro_schema_registry.rb +34 -0
  62. data/lib/deimos/schema_backends/avro_validation.rb +21 -0
  63. data/lib/deimos/schema_backends/base.rb +150 -0
  64. data/lib/deimos/schema_backends/mock.rb +42 -0
  65. data/lib/deimos/shared_config.rb +63 -0
  66. data/lib/deimos/test_helpers.rb +360 -0
  67. data/lib/deimos/tracing/datadog.rb +35 -0
  68. data/lib/deimos/tracing/mock.rb +40 -0
  69. data/lib/deimos/tracing/provider.rb +29 -0
  70. data/lib/deimos/utils/db_poller.rb +150 -0
  71. data/lib/deimos/utils/db_producer.rb +243 -0
  72. data/lib/deimos/utils/deadlock_retry.rb +68 -0
  73. data/lib/deimos/utils/inline_consumer.rb +150 -0
  74. data/lib/deimos/utils/lag_reporter.rb +175 -0
  75. data/lib/deimos/utils/schema_controller_mixin.rb +115 -0
  76. data/lib/deimos/version.rb +5 -0
  77. data/lib/generators/deimos/active_record/templates/migration.rb.tt +28 -0
  78. data/lib/generators/deimos/active_record/templates/model.rb.tt +5 -0
  79. data/lib/generators/deimos/active_record_generator.rb +79 -0
  80. data/lib/generators/deimos/db_backend/templates/migration +25 -0
  81. data/lib/generators/deimos/db_backend/templates/rails3_migration +31 -0
  82. data/lib/generators/deimos/db_backend_generator.rb +48 -0
  83. data/lib/generators/deimos/db_poller/templates/migration +11 -0
  84. data/lib/generators/deimos/db_poller/templates/rails3_migration +16 -0
  85. data/lib/generators/deimos/db_poller_generator.rb +48 -0
  86. data/lib/tasks/deimos.rake +34 -0
  87. data/spec/active_record_batch_consumer_spec.rb +481 -0
  88. data/spec/active_record_consume/batch_slicer_spec.rb +42 -0
  89. data/spec/active_record_consume/schema_model_converter_spec.rb +105 -0
  90. data/spec/active_record_consumer_spec.rb +154 -0
  91. data/spec/active_record_producer_spec.rb +85 -0
  92. data/spec/backends/base_spec.rb +10 -0
  93. data/spec/backends/db_spec.rb +54 -0
  94. data/spec/backends/kafka_async_spec.rb +11 -0
  95. data/spec/backends/kafka_spec.rb +11 -0
  96. data/spec/batch_consumer_spec.rb +256 -0
  97. data/spec/config/configuration_spec.rb +248 -0
  98. data/spec/consumer_spec.rb +209 -0
  99. data/spec/deimos_spec.rb +169 -0
  100. data/spec/generators/active_record_generator_spec.rb +56 -0
  101. data/spec/handlers/my_batch_consumer.rb +10 -0
  102. data/spec/handlers/my_consumer.rb +10 -0
  103. data/spec/kafka_listener_spec.rb +55 -0
  104. data/spec/kafka_source_spec.rb +381 -0
  105. data/spec/kafka_topic_info_spec.rb +111 -0
  106. data/spec/message_spec.rb +19 -0
  107. data/spec/phobos.bad_db.yml +73 -0
  108. data/spec/phobos.yml +77 -0
  109. data/spec/producer_spec.rb +498 -0
  110. data/spec/rake_spec.rb +19 -0
  111. data/spec/schema_backends/avro_base_shared.rb +199 -0
  112. data/spec/schema_backends/avro_local_spec.rb +32 -0
  113. data/spec/schema_backends/avro_schema_registry_spec.rb +32 -0
  114. data/spec/schema_backends/avro_validation_spec.rb +24 -0
  115. data/spec/schema_backends/base_spec.rb +33 -0
  116. data/spec/schemas/com/my-namespace/Generated.avsc +71 -0
  117. data/spec/schemas/com/my-namespace/MyNestedSchema.avsc +62 -0
  118. data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
  119. data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
  120. data/spec/schemas/com/my-namespace/MySchemaCompound-key.avsc +18 -0
  121. data/spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc +18 -0
  122. data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
  123. data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
  124. data/spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc +32 -0
  125. data/spec/schemas/com/my-namespace/Wibble.avsc +43 -0
  126. data/spec/schemas/com/my-namespace/Widget.avsc +27 -0
  127. data/spec/schemas/com/my-namespace/WidgetTheSecond.avsc +27 -0
  128. data/spec/schemas/com/my-namespace/request/CreateTopic.avsc +11 -0
  129. data/spec/schemas/com/my-namespace/request/Index.avsc +11 -0
  130. data/spec/schemas/com/my-namespace/request/UpdateRequest.avsc +11 -0
  131. data/spec/schemas/com/my-namespace/response/CreateTopic.avsc +11 -0
  132. data/spec/schemas/com/my-namespace/response/Index.avsc +11 -0
  133. data/spec/schemas/com/my-namespace/response/UpdateResponse.avsc +11 -0
  134. data/spec/spec_helper.rb +267 -0
  135. data/spec/utils/db_poller_spec.rb +320 -0
  136. data/spec/utils/db_producer_spec.rb +514 -0
  137. data/spec/utils/deadlock_retry_spec.rb +74 -0
  138. data/spec/utils/inline_consumer_spec.rb +31 -0
  139. data/spec/utils/lag_reporter_spec.rb +76 -0
  140. data/spec/utils/platform_schema_validation_spec.rb +0 -0
  141. data/spec/utils/schema_controller_mixin_spec.rb +84 -0
  142. data/support/deimos-solo.png +0 -0
  143. data/support/deimos-with-name-next.png +0 -0
  144. data/support/deimos-with-name.png +0 -0
  145. data/support/flipp-logo.png +0 -0
  146. metadata +551 -0
data/spec/rake_spec.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rake'
4
+ require 'rails'
5
+ Rails.logger = Logger.new(STDOUT)
6
+ load("#{__dir__}/../lib/tasks/deimos.rake")
7
+
8
+ if Rake.application.lookup(:environment).nil?
9
+ Rake::Task.define_task(:environment)
10
+ end
11
+
12
+ describe 'Rakefile' do
13
+ it 'should start listeners' do
14
+ runner = instance_double(Phobos::CLI::Runner)
15
+ expect(Phobos::CLI::Runner).to receive(:new).and_return(runner)
16
+ expect(runner).to receive(:run!)
17
+ Rake::Task['deimos:start'].invoke
18
+ end
19
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'deimos/schema_backends/avro_base'
4
+
5
+ RSpec.shared_examples_for('an Avro backend') do
6
+ let(:backend) { described_class.new(schema: 'MySchema', namespace: 'com.my-namespace') }
7
+
8
+ let(:full_schema) do
9
+ {
10
+ 'type' => 'record',
11
+ 'name' => 'schema1',
12
+ 'namespace' => 'com.my-namespace',
13
+ 'fields' => [
14
+ {
15
+ 'name' => 'int-field',
16
+ 'type' => 'int'
17
+ },
18
+ {
19
+ 'name' => 'long-field',
20
+ 'type' => 'long'
21
+ },
22
+ {
23
+ 'name' => 'float-field',
24
+ 'type' => 'float'
25
+ },
26
+ {
27
+ 'name' => 'double-field',
28
+ 'type' => 'double'
29
+ },
30
+ {
31
+ 'name' => 'string-field',
32
+ 'type' => 'string'
33
+ },
34
+ {
35
+ 'name' => 'boolean-field',
36
+ 'type' => 'boolean'
37
+ },
38
+ {
39
+ 'name' => 'union-field',
40
+ 'type' => %w(null string)
41
+ },
42
+ {
43
+ 'name' => 'union-int-field',
44
+ 'type' => %w(null int)
45
+ },
46
+ {
47
+ 'name' => 'timestamp-millis-field',
48
+ 'type' => {
49
+ 'type' => 'long',
50
+ 'logicalType' => 'timestamp-millis'
51
+ }
52
+ },
53
+ {
54
+ 'name' => 'timestamp-micros-field',
55
+ 'type' => {
56
+ 'type' => 'long',
57
+ 'logicalType' => 'timestamp-micros'
58
+ }
59
+ }
60
+ ]
61
+ }
62
+ end
63
+
64
+ specify('#encode_key') do
65
+ expect(backend).to receive(:encode).
66
+ with({ 'test_id' => 1 }, { schema: 'MySchema_key', topic: 'topic' }).and_return('itsme')
67
+ expect(backend.encode_key('test_id', 1, topic: 'topic')).to eq('itsme')
68
+ expect(backend.schema_store.find('MySchema_key', 'com.my-namespace').to_avro).
69
+ to eq(
70
+ 'doc' => 'Key for com.my-namespace.MySchema - autogenerated by Deimos',
71
+ 'fields' => [
72
+ { 'name' => 'test_id', 'type' => 'string' }
73
+ ],
74
+ 'name' => 'MySchema_key',
75
+ 'namespace' => 'com.my-namespace',
76
+ 'type' => 'record'
77
+ )
78
+ end
79
+
80
+ specify('#decode_key') do
81
+ expect(backend).to receive(:decode).
82
+ with('payload', schema: 'MySchema_key').
83
+ and_return('test_id' => 1)
84
+ expect(backend.decode_key('payload', 'test_id')).to eq(1)
85
+ end
86
+
87
+ describe('#validate') do
88
+ it 'should pass valid schemas' do
89
+ expect {
90
+ backend.validate({ 'test_id' => 'hi', 'some_int' => 4 }, { schema: 'MySchema' })
91
+ }.not_to raise_error
92
+ end
93
+
94
+ it 'should fail invalid schemas' do
95
+ expect {
96
+ backend.validate({ 'test_id2' => 'hi', 'some_int' => 4 }, { schema: 'MySchema' })
97
+ }.to raise_error(Avro::SchemaValidator::ValidationError)
98
+ end
99
+
100
+ end
101
+
102
+ describe '#coerce' do
103
+ let(:payload) do
104
+ {
105
+ 'int-field' => 1,
106
+ 'long-field' => 11_111_111_111_111_111_111,
107
+ 'float-field' => 1.0,
108
+ 'double-field' => 2.0,
109
+ 'string-field' => 'hi mom',
110
+ 'boolean-field' => true,
111
+ 'union-field' => nil,
112
+ 'union-int-field' => nil,
113
+ 'timestamp-millis-field' => Time.utc(2020, 11, 12, 13, 14, 15, 909_090),
114
+ 'timestamp-micros-field' => Time.utc(2020, 11, 12, 13, 14, 15, 909_090)
115
+ }
116
+ end
117
+
118
+ before(:each) do
119
+ backend.schema_store.add_schema(full_schema)
120
+ backend.schema = 'schema1'
121
+ end
122
+
123
+ it 'should leave numbers as is' do
124
+ result = backend.coerce(payload)
125
+ expect(result['int-field']).to eq(1)
126
+ expect(result['long-field']).to eq(11_111_111_111_111_111_111)
127
+ expect(result['float-field']).to eq(1.0)
128
+ expect(result['double-field']).to eq(2.0)
129
+ expect(result['boolean-field']).to eq(true)
130
+ expect(result['union-field']).to eq(nil)
131
+ end
132
+
133
+ it 'should coerce strings to numbers' do
134
+ result = backend.coerce(payload.merge(
135
+ 'int-field' => '1',
136
+ 'long-field' => '123',
137
+ 'float-field' => '1.1',
138
+ 'double-field' => '2.1'
139
+ ))
140
+ expect(result['int-field']).to eq(1)
141
+ expect(result['long-field']).to eq(123)
142
+ expect(result['float-field']).to eq(1.1)
143
+ expect(result['double-field']).to eq(2.1)
144
+ end
145
+
146
+ it 'should coerce Time to number' do
147
+ result = backend.coerce(payload.merge('int-field' => Time.find_zone('UTC').local(2019, 5, 5)))
148
+ expect(result['int-field']).to eq(1_557_014_400)
149
+ end
150
+
151
+ it 'should coerce symbols to string' do
152
+ result = backend.coerce(payload.merge('string-field' => :itsme))
153
+ expect(result['string-field']).to eq('itsme')
154
+ end
155
+
156
+ it 'should convert string-like things to string' do
157
+ stringy = Class.new do
158
+ # :nodoc:
159
+ def initialize(str)
160
+ @st = str
161
+ end
162
+
163
+ # :nodoc:
164
+ def to_s
165
+ @st
166
+ end
167
+
168
+ # :nodoc:
169
+ def to_str
170
+ @st
171
+ end
172
+ end
173
+ stub_const('Stringy', stringy)
174
+ result = backend.coerce(payload.merge('string-field' => Stringy.new('itsyou')))
175
+ expect(result['string-field']).to eq('itsyou')
176
+ end
177
+
178
+ it 'should convert null to false' do
179
+ result = backend.coerce(payload.merge('boolean-field' => nil))
180
+ expect(result['boolean-field']).to eq(false)
181
+ end
182
+
183
+ it 'should convert unions' do
184
+ result = backend.coerce(payload.merge('union-field' => :itsme))
185
+ expect(result['union-field']).to eq('itsme')
186
+ end
187
+
188
+ it 'should not convert timestamp-millis' do
189
+ result = backend.coerce(payload)
190
+ expect(result['timestamp-millis-field']).to eq(Time.utc(2020, 11, 12, 13, 14, 15, 909_090))
191
+ end
192
+
193
+ it 'should not convert timestamp-micros' do
194
+ result = backend.coerce(payload)
195
+ expect(result['timestamp-micros-field']).to eq(Time.utc(2020, 11, 12, 13, 14, 15, 909_090))
196
+ end
197
+ end
198
+
199
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'avro_base_shared'
4
+ require 'deimos/schema_backends/avro_local'
5
+
6
+ RSpec.describe Deimos::SchemaBackends::AvroLocal do
7
+ let(:payload) do
8
+ {
9
+ 'test_id' => 'some string',
10
+ 'some_int' => 3
11
+ }
12
+ end
13
+ let(:backend) { described_class.new(schema: 'MySchema', namespace: 'com.my-namespace') }
14
+
15
+ it_should_behave_like 'an Avro backend'
16
+
17
+ it 'should encode and decode correctly' do
18
+ avro_turf = instance_double(AvroTurf)
19
+ expect(avro_turf).to receive(:encode).
20
+ with(payload, schema_name: 'MySchema', namespace: 'com.my-namespace').
21
+ and_return('encoded-payload')
22
+ expect(avro_turf).to receive(:decode).
23
+ with('encoded-payload', schema_name: 'MySchema', namespace: 'com.my-namespace').
24
+ and_return(payload)
25
+ allow(backend).to receive(:avro_turf).and_return(avro_turf)
26
+ results = backend.encode(payload)
27
+ expect(results).to eq('encoded-payload')
28
+ results = backend.decode(results)
29
+ expect(results).to eq(payload)
30
+ end
31
+
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'avro_base_shared'
4
+ require 'deimos/schema_backends/avro_schema_registry'
5
+
6
+ RSpec.describe Deimos::SchemaBackends::AvroSchemaRegistry do
7
+ let(:payload) do
8
+ {
9
+ 'test_id' => 'some string',
10
+ 'some_int' => 3
11
+ }
12
+ end
13
+ let(:backend) { described_class.new(schema: 'MySchema', namespace: 'com.my-namespace') }
14
+
15
+ it_should_behave_like 'an Avro backend'
16
+
17
+ it 'should encode and decode correctly' do
18
+ avro_turf = instance_double(AvroTurf::Messaging)
19
+ expect(avro_turf).to receive(:encode).
20
+ with(payload, schema_name: 'MySchema', subject: 'topic').
21
+ and_return('encoded-payload')
22
+ expect(avro_turf).to receive(:decode).
23
+ with('encoded-payload', schema_name: 'MySchema').
24
+ and_return(payload)
25
+ allow(backend).to receive(:avro_turf_messaging).and_return(avro_turf)
26
+ results = backend.encode(payload, topic: 'topic')
27
+ expect(results).to eq('encoded-payload')
28
+ results = backend.decode(results)
29
+ expect(results).to eq(payload)
30
+ end
31
+
32
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'avro_base_shared'
4
+ require 'deimos/schema_backends/avro_validation'
5
+
6
+ RSpec.describe Deimos::SchemaBackends::AvroValidation do
7
+ let(:payload) do
8
+ {
9
+ 'test_id' => 'some string',
10
+ 'some_int' => 3
11
+ }
12
+ end
13
+ let(:backend) { described_class.new(schema: 'MySchema', namespace: 'com.my-namespace') }
14
+
15
+ it_should_behave_like 'an Avro backend'
16
+
17
+ it 'should encode and decode correctly' do
18
+ results = backend.encode(payload)
19
+ expect(results).to eq(payload)
20
+ results = backend.decode(results)
21
+ expect(results).to eq(payload)
22
+ end
23
+
24
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Deimos::SchemaBackends::Base do
4
+ let(:backend) { described_class.new(schema: 'schema', namespace: 'namespace') }
5
+ let(:payload) { { foo: 1 } }
6
+
7
+ it 'should validate on encode' do
8
+ expect(backend).to receive(:validate).with(payload, schema: 'schema')
9
+ expect(backend).to receive(:encode_payload).with(payload, schema: 'schema', topic: 'topic')
10
+ backend.encode(payload, topic: 'topic')
11
+ end
12
+
13
+ it 'should validate and encode a passed schema' do
14
+ expect(backend).to receive(:validate).with(payload, schema: 'schema2')
15
+ expect(backend).to receive(:encode_payload).with(payload, schema: 'schema2', topic: 'topic')
16
+ backend.encode(payload, schema: 'schema2', topic: 'topic')
17
+ end
18
+
19
+ it 'should decode a schema' do
20
+ expect(backend).to receive(:decode_payload).with(payload, schema: 'schema')
21
+ backend.decode(payload)
22
+ end
23
+
24
+ it 'should decode a passed schema' do
25
+ expect(backend).to receive(:decode_payload).with(payload, schema: 'schema2')
26
+ backend.decode(payload, schema: 'schema2')
27
+ end
28
+
29
+ it 'should return nil if passed nil' do
30
+ expect(backend.decode(nil, schema: 'schema2')).to be_nil
31
+ end
32
+
33
+ end
@@ -0,0 +1,71 @@
1
+ {
2
+ "namespace": "com.my-namespace",
3
+ "name": "Generated",
4
+ "type": "record",
5
+ "doc": "Test schema",
6
+ "fields": [
7
+ {
8
+ "name": "a_string",
9
+ "type": "string"
10
+ },
11
+ {
12
+ "name": "a_int",
13
+ "type": "int"
14
+ },
15
+ {
16
+ "name": "a_long",
17
+ "type": "long"
18
+ },
19
+ {
20
+ "name": "a_float",
21
+ "type": "float"
22
+ },
23
+ {
24
+ "name": "a_double",
25
+ "type": "double"
26
+ },
27
+ {
28
+ "name": "an_enum",
29
+ "type": {
30
+ "type": "enum",
31
+ "name": "AnEnum",
32
+ "symbols": ["sym1", "sym2"]
33
+ }
34
+ },
35
+ {
36
+ "name": "an_array",
37
+ "type": {
38
+ "type": "array",
39
+ "items": "int"
40
+ }
41
+ },
42
+ {
43
+ "name": "a_map",
44
+ "type": {
45
+ "type": "map",
46
+ "values": "string"
47
+ }
48
+ },
49
+ {
50
+ "name": "timestamp",
51
+ "type": "string"
52
+ },
53
+ {
54
+ "name": "message_id",
55
+ "type": "string"
56
+ },
57
+ {
58
+ "name": "a_record",
59
+ "type": {
60
+ "type": "record",
61
+ "name": "ARecord",
62
+ "fields": [
63
+ {
64
+ "name": "a_record_field",
65
+ "type": "string"
66
+ }
67
+ ]
68
+ }
69
+ }
70
+ ]
71
+ }
@@ -0,0 +1,62 @@
1
+ {
2
+ "namespace": "com.my-namespace",
3
+ "name": "MyNestedSchema",
4
+ "type": "record",
5
+ "doc": "Test schema",
6
+ "fields": [
7
+ {
8
+ "name": "test_id",
9
+ "type": "string",
10
+ "doc": "test string"
11
+ },
12
+ {
13
+ "name": "test_float",
14
+ "type": "float",
15
+ "doc": "test float"
16
+ },
17
+ {
18
+ "name": "test_array",
19
+ "type": {
20
+ "type": "array",
21
+ "items": "string"
22
+ }
23
+ },
24
+ {
25
+ "name": "some_nested_record",
26
+ "doc": "some nested record",
27
+ "type": {
28
+ "name": "MyNestedRecord",
29
+ "type": "record",
30
+ "fields": [
31
+ {
32
+ "name": "some_int",
33
+ "type": "int",
34
+ "doc": "some int"
35
+ },
36
+ {
37
+ "name": "some_float",
38
+ "type": "float",
39
+ "doc": "some float"
40
+ },
41
+ {
42
+ "name": "some_string",
43
+ "type": "string",
44
+ "doc": "some string"
45
+ },
46
+ {
47
+ "name": "some_optional_int",
48
+ "type": [ "null", "int" ],
49
+ "doc": "some optional int",
50
+ "default": null
51
+ }
52
+ ]
53
+ }
54
+ },
55
+ {
56
+ "name": "some_optional_record",
57
+ "doc": "some optional record",
58
+ "type": [ "null", "MyNestedRecord" ],
59
+ "default": null
60
+ }
61
+ ]
62
+ }