rflow 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +5 -0
- data/NOTES +187 -0
- data/README +0 -0
- data/Rakefile +16 -0
- data/bin/rflow +215 -0
- data/example/basic_config.rb +49 -0
- data/example/basic_extensions.rb +142 -0
- data/example/http_config.rb +21 -0
- data/example/http_extensions.rb +262 -0
- data/lib/rflow.rb +440 -0
- data/lib/rflow/component.rb +192 -0
- data/lib/rflow/component/port.rb +150 -0
- data/lib/rflow/components.rb +10 -0
- data/lib/rflow/components/raw.rb +26 -0
- data/lib/rflow/components/raw/extensions.rb +18 -0
- data/lib/rflow/configuration.rb +290 -0
- data/lib/rflow/configuration/component.rb +27 -0
- data/lib/rflow/configuration/connection.rb +98 -0
- data/lib/rflow/configuration/migrations/20010101000001_create_settings.rb +14 -0
- data/lib/rflow/configuration/migrations/20010101000002_create_components.rb +19 -0
- data/lib/rflow/configuration/migrations/20010101000003_create_ports.rb +24 -0
- data/lib/rflow/configuration/migrations/20010101000004_create_connections.rb +27 -0
- data/lib/rflow/configuration/port.rb +30 -0
- data/lib/rflow/configuration/ruby_dsl.rb +183 -0
- data/lib/rflow/configuration/setting.rb +67 -0
- data/lib/rflow/configuration/uuid_keyed.rb +18 -0
- data/lib/rflow/connection.rb +59 -0
- data/lib/rflow/connections.rb +2 -0
- data/lib/rflow/connections/zmq_connection.rb +101 -0
- data/lib/rflow/message.rb +191 -0
- data/lib/rflow/port.rb +4 -0
- data/lib/rflow/util.rb +19 -0
- data/lib/rflow/version.rb +3 -0
- data/rflow.gemspec +42 -0
- data/schema/message.avsc +36 -0
- data/schema/raw.avsc +9 -0
- data/spec/fixtures/config_ints.rb +61 -0
- data/spec/fixtures/extensions_ints.rb +141 -0
- data/spec/rflow_configuration_spec.rb +73 -0
- data/spec/rflow_message_data_raw.rb +26 -0
- data/spec/rflow_message_data_spec.rb +60 -0
- data/spec/rflow_message_spec.rb +182 -0
- data/spec/rflow_spec.rb +100 -0
- data/spec/schema_spec.rb +28 -0
- data/spec/spec_helper.rb +37 -0
- data/temp.rb +295 -0
- metadata +270 -0
data/schema/message.avsc
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
{
|
2
|
+
"type": "record",
|
3
|
+
"name": "Message",
|
4
|
+
"namespace": "org.rflow",
|
5
|
+
"aliases": [],
|
6
|
+
"fields": [
|
7
|
+
{"name": "data_type_name", "type": "string"},
|
8
|
+
{"name": "provenance",
|
9
|
+
"type": {
|
10
|
+
"type": "array",
|
11
|
+
"items": {
|
12
|
+
"type": "record",
|
13
|
+
"name": "ProcessingEvent",
|
14
|
+
"namespace": "org.rflow",
|
15
|
+
"aliases": [],
|
16
|
+
"fields": [
|
17
|
+
{"name": "component_instance_uuid", "type": "string"},
|
18
|
+
{"name": "started_at", "type": ["string", "null"]},
|
19
|
+
{"name": "completed_at", "type": ["string", "null"]},
|
20
|
+
{"name": "context", "type": ["bytes", "null"]}
|
21
|
+
]
|
22
|
+
}
|
23
|
+
}
|
24
|
+
},
|
25
|
+
{"name": "data_serialization_type",
|
26
|
+
"type": {
|
27
|
+
"type": "enum",
|
28
|
+
"name": "DataSerializationType",
|
29
|
+
"symbols": ["avro", "xml"]
|
30
|
+
}
|
31
|
+
},
|
32
|
+
{"name": "data_schema", "type": "string"},
|
33
|
+
{"name": "data", "type": "bytes"}
|
34
|
+
]
|
35
|
+
}
|
36
|
+
|
data/schema/raw.avsc
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Meat of the config file. Stuff above this should probably be in
|
2
|
+
# separate gems and/or files that are brought in at runtime.
|
3
|
+
RFlow::Configuration::RubyDSL.configure do |config|
|
4
|
+
# Configure the settings, which include paths for various files, log
|
5
|
+
# levels, and component specific stuffs
|
6
|
+
config.setting('rflow.log_level', 'DEBUG')
|
7
|
+
config.setting('rflow.application_directory_path', '../tmp')
|
8
|
+
|
9
|
+
config.setting('rflow.application_name', 'testapp')
|
10
|
+
|
11
|
+
# Add schemas to the list of available. Not convinced this is necessary
|
12
|
+
# config.schema('schemaname', 'schematype', 'schemadata')
|
13
|
+
|
14
|
+
# Instantiate components
|
15
|
+
# config.component 'generate_ints1', 'RFlow::Components::GenerateIntegerSequence', 'start' => 0, 'finish' => 10, 'step' => 3, 'interval_seconds' => 1
|
16
|
+
# config.component 'generate_ints2', 'RFlow::Components::GenerateIntegerSequence', 'start' => 20, 'finish' => 30
|
17
|
+
# config.component 'filter', 'RFlow::Components::RubyProcFilter', 'filter_proc_string' => 'lambda {|message| true}'
|
18
|
+
# config.component 'replicate', 'RFlow::Components::Replicate'
|
19
|
+
# config.component 'output1', 'RFlow::Components::FileOutput', 'output_file_path' => '/tmp/crap1'
|
20
|
+
# config.component 'output2', 'RFlow::Components::FileOutput', 'output_file_path' => '/tmp/crap2'
|
21
|
+
|
22
|
+
# Hook components together
|
23
|
+
# config.connect 'generate_ints#out' => 'filter#in'
|
24
|
+
# config.connect 'filter#filtered' => 'replicate#in'
|
25
|
+
# config.connect 'replicate#out[0]' => 'simple#in'
|
26
|
+
# config.connect 'replicate#out[one]' => 'complex#in'
|
27
|
+
# config.connect 'simple#out' => 'output#in'
|
28
|
+
# config.connect 'complex#out' => 'output#in'
|
29
|
+
|
30
|
+
# config.connect 'generate_ints1#out' => 'filter#in'
|
31
|
+
# config.connect 'generate_ints2#out' => 'filter#in'
|
32
|
+
# config.connect 'filter#filtered' => 'replicate#in'
|
33
|
+
# config.connect 'replicate#out[1]' => 'output1#in'
|
34
|
+
# config.connect 'replicate#out[2]' => 'output2#in'
|
35
|
+
# Some tests that should fail
|
36
|
+
# output should not have an 'out' ports
|
37
|
+
# config.connect 'output#out' => 'simple#in'
|
38
|
+
|
39
|
+
config.component 'generate_ints', 'RFlow::Components::GenerateIntegerSequence', 'start' => 20, 'finish' => 30
|
40
|
+
config.component 'output', 'RFlow::Components::FileOutput', 'output_file_path' => '../tmp/out'
|
41
|
+
config.component 'output2', 'RFlow::Components::FileOutput', 'output_file_path' => '../tmp/out2'
|
42
|
+
config.component 'output_even', 'RFlow::Components::FileOutput', 'output_file_path' => '../tmp/out_even'
|
43
|
+
config.component 'output_odd', 'RFlow::Components::FileOutput', 'output_file_path' => '../tmp/out_odd'
|
44
|
+
config.component 'output_even_odd', 'RFlow::Components::FileOutput', 'output_file_path' => '../tmp/out_even_odd'
|
45
|
+
|
46
|
+
config.connect 'generate_ints#out' => 'output#in'
|
47
|
+
config.connect 'generate_ints#out' => 'output2#in'
|
48
|
+
config.connect 'generate_ints#even_odd_out[even]' => 'output_even#in'
|
49
|
+
config.connect 'generate_ints#even_odd_out[odd]' => 'output_odd#in'
|
50
|
+
config.connect 'generate_ints#even_odd_out' => 'output_even_odd#in'
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
config.component 'generate_ints2', 'RFlow::Components::GenerateIntegerSequence', 'start' => 20, 'finish' => 30
|
55
|
+
config.component 'output_even_odd2', 'RFlow::Components::FileOutput', 'output_file_path' => '../tmp/out_even_odd2'
|
56
|
+
|
57
|
+
config.connect 'generate_ints2#even_odd_out' => 'output_even_odd2#in'
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# This will/should bring in available components and their schemas
|
2
|
+
require 'rflow/components'
|
3
|
+
require 'rflow/message'
|
4
|
+
|
5
|
+
#RFlow::Configuration.add_available_data_schema RFlow::Message::Data::AvroSchema.new('Integer', long_integer_schema)
|
6
|
+
|
7
|
+
# Example of creating and registering a data extension
|
8
|
+
module SimpleDataExtension
|
9
|
+
# Use this to default/verify the data in data_object
|
10
|
+
def self.extended(base_data)
|
11
|
+
base_data.data_object
|
12
|
+
end
|
13
|
+
|
14
|
+
def my_method; end
|
15
|
+
end
|
16
|
+
RFlow::Configuration.add_available_data_extension('RFlow::Message::Data::Integer', SimpleDataExtension)
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
# Example of creating and registering a new schema
|
21
|
+
long_integer_schema = '{"type": "long"}'
|
22
|
+
RFlow::Configuration.add_available_data_type('RFlow::Message::Data::Integer', 'avro', long_integer_schema)
|
23
|
+
|
24
|
+
|
25
|
+
class RFlow::Components::GenerateIntegerSequence < RFlow::Component
|
26
|
+
output_port :out
|
27
|
+
output_port :even_odd_out
|
28
|
+
|
29
|
+
def configure!(config)
|
30
|
+
@start = config['start'].to_i
|
31
|
+
@finish = config['finish'].to_i
|
32
|
+
@step = config['step'] ? config['step'].to_i : 1
|
33
|
+
# If interval seconds is not given, it will default to 0
|
34
|
+
@interval_seconds = config['interval_seconds'].to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
# Note that this uses the timer (sometimes with 0 interval) so as
|
38
|
+
# not to block the reactor
|
39
|
+
def run!
|
40
|
+
timer = EM::PeriodicTimer.new(@interval_seconds) do
|
41
|
+
message = RFlow::Message.new('RFlow::Message::Data::Integer')
|
42
|
+
message.data.data_object = @start
|
43
|
+
out.send_message message
|
44
|
+
if @start % 2 == 0
|
45
|
+
even_odd_out['even'].send_message message
|
46
|
+
else
|
47
|
+
even_odd_out['odd'].send_message message
|
48
|
+
end
|
49
|
+
|
50
|
+
@start += @step
|
51
|
+
timer.cancel if @start > @finish
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class RFlow::Components::Replicate < RFlow::Component
|
58
|
+
input_port :in
|
59
|
+
output_port :out
|
60
|
+
output_port :errored
|
61
|
+
|
62
|
+
def process_message(input_port, input_port_key, connection, message)
|
63
|
+
puts "Processing message in Replicate"
|
64
|
+
out.each do |connections|
|
65
|
+
puts "Replicating"
|
66
|
+
begin
|
67
|
+
connections.send_message message
|
68
|
+
rescue Exception => e
|
69
|
+
puts "Exception #{e.message}"
|
70
|
+
errored.send_message message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
puts "Before RubyProcFilter"
|
77
|
+
class RFlow::Components::RubyProcFilter < RFlow::Component
|
78
|
+
input_port :in
|
79
|
+
output_port :filtered
|
80
|
+
output_port :dropped
|
81
|
+
output_port :errored
|
82
|
+
|
83
|
+
|
84
|
+
def configure!(config)
|
85
|
+
@filter_proc = eval("lambda {|message| #{config['filter_proc_string']} }")
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_message(input_port, input_port_key, connection, message)
|
89
|
+
puts "Processing message in RubyProcFilter"
|
90
|
+
begin
|
91
|
+
if @filter_proc.call(message)
|
92
|
+
filtered.send_message message
|
93
|
+
else
|
94
|
+
dropped.send_message message
|
95
|
+
end
|
96
|
+
rescue Exception => e
|
97
|
+
puts "Attempting to send message to errored #{e.message}"
|
98
|
+
errored.send_message message
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
puts "Before FileOutput"
|
104
|
+
class RFlow::Components::FileOutput < RFlow::Component
|
105
|
+
attr_accessor :output_file_path, :output_file
|
106
|
+
input_port :in
|
107
|
+
|
108
|
+
def configure!(config)
|
109
|
+
self.output_file_path = config['output_file_path']
|
110
|
+
self.output_file = File.new output_file_path, 'w+'
|
111
|
+
end
|
112
|
+
|
113
|
+
#def run!; end
|
114
|
+
|
115
|
+
def process_message(input_port, input_port_key, connection, message)
|
116
|
+
puts "About to output to a file #{output_file_path}"
|
117
|
+
output_file.puts message.data.data_object.inspect
|
118
|
+
output_file.flush
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
def cleanup
|
123
|
+
output_file.close
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
# TODO: Ensure that all the following methods work as they are
|
129
|
+
# supposed to. This is the interface that I'm adhering to
|
130
|
+
class SimpleComponent < RFlow::Component
|
131
|
+
input_port :in
|
132
|
+
output_port :out
|
133
|
+
|
134
|
+
def configure!(config); end
|
135
|
+
def run!; end
|
136
|
+
def process_message(input_port, input_port_key, connection, message); end
|
137
|
+
def shutdown!; end
|
138
|
+
def cleanup!; end
|
139
|
+
end
|
140
|
+
|
141
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
require 'rflow/configuration'
|
4
|
+
|
5
|
+
|
6
|
+
describe RFlow::Configuration do
|
7
|
+
before(:each) do
|
8
|
+
# RFlow::Configuration.available_data_types.clear
|
9
|
+
# RFlow::Configuration.available_data_extensions.clear
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe '.add_available_data_type' do
|
14
|
+
context 'if passed a data_serialization that is not avro or xml' do
|
15
|
+
it "should throw an exception" do
|
16
|
+
expect do
|
17
|
+
RFlow::Configuration.add_available_data_type('A', 'boom', 'schema')
|
18
|
+
end.to raise_error(ArgumentError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not update the available_data_types" do
|
22
|
+
num_types = RFlow::Configuration.available_data_types.size
|
23
|
+
RFlow::Configuration.add_available_data_type('A', 'boom', 'schema') rescue nil
|
24
|
+
RFlow::Configuration.available_data_types.should have(num_types).items
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "Data Extensions" do
|
30
|
+
|
31
|
+
describe ".add_available_data_extension" do
|
32
|
+
context 'if passed a non-module data extension' do
|
33
|
+
it "should throw an exception" do
|
34
|
+
expect do
|
35
|
+
RFlow::Configuration.add_available_data_extension('data_type', 'not a Module')
|
36
|
+
end.to raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "if passed a valid Module as a data extension" do
|
41
|
+
it "should update the available_data_extensions" do
|
42
|
+
num_extensions = RFlow::Configuration.available_data_extensions['data_type'].size
|
43
|
+
expect do
|
44
|
+
RFlow::Configuration.add_available_data_extension('data_type', Module.new)
|
45
|
+
end.to_not raise_error
|
46
|
+
RFlow::Configuration.available_data_extensions['data_type'].should have(num_extensions+1).items
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should perform simple 'prefix'-based inheritance for extensions" do
|
52
|
+
RFlow::Configuration.add_available_data_extension('A', A = Module.new)
|
53
|
+
RFlow::Configuration.add_available_data_extension('A::B', B = Module.new)
|
54
|
+
RFlow::Configuration.add_available_data_extension('A::B::C', C = Module.new)
|
55
|
+
RFlow::Configuration.add_available_data_extension('A::B::C::D', D = Module.new)
|
56
|
+
|
57
|
+
RFlow::Configuration.available_data_extensions['A'].should have(1).item
|
58
|
+
RFlow::Configuration.available_data_extensions['A'].should == [A]
|
59
|
+
|
60
|
+
RFlow::Configuration.available_data_extensions['A::B'].should have(2).item
|
61
|
+
RFlow::Configuration.available_data_extensions['A::B'].should == [A, B]
|
62
|
+
|
63
|
+
RFlow::Configuration.available_data_extensions['A::B::C'].should have(3).item
|
64
|
+
RFlow::Configuration.available_data_extensions['A::B::C'].should == [A, B, C]
|
65
|
+
|
66
|
+
RFlow::Configuration.available_data_extensions['A::B::C::D'].should have(4).item
|
67
|
+
RFlow::Configuration.available_data_extensions['A::B::C::D'].should == [A, B, C, D]
|
68
|
+
|
69
|
+
RFlow::Configuration.available_data_extensions['A::B::C::D::E'].should have(4).item
|
70
|
+
RFlow::Configuration.available_data_extensions['A::B::C::D::E'].should == [A, B, C, D]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
require 'rflow/components/raw'
|
4
|
+
|
5
|
+
describe 'RFlow::Message::Data::Raw Avro Schema' do
|
6
|
+
before(:each) do
|
7
|
+
@schema_string = RFlow::Configuration.available_data_types['RFlow::Message::Data::Raw']['avro']
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should load the schema" do
|
11
|
+
@schema_string.should_not == nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should encode and decode an object" do
|
15
|
+
raw = {'raw' => 'rawdata'}
|
16
|
+
|
17
|
+
expect {encode_avro(@schema_string, raw)}.to_not raise_error
|
18
|
+
avro_encoded_raw = encode_avro(@schema_string, raw)
|
19
|
+
|
20
|
+
expect {decode_avro(@schema_string, avro_encoded_raw)}.to_not raise_error
|
21
|
+
decoded_raw = decode_avro(@schema_string, avro_encoded_raw)
|
22
|
+
|
23
|
+
decoded_raw.should == raw
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
require 'rflow/message'
|
4
|
+
|
5
|
+
describe RFlow::Message::Data do
|
6
|
+
before(:all) do
|
7
|
+
@string = 'this is a string to be serialized'
|
8
|
+
@invalid_avro_schema_string = 'invalid schema'
|
9
|
+
@valid_avro_string_schema_string = '{"type": "string"}'
|
10
|
+
@avro_serialized_string = encode_avro(@valid_avro_string_schema_string, @string)
|
11
|
+
end
|
12
|
+
|
13
|
+
context "if created without a schema" do
|
14
|
+
it "should throw an exception" do
|
15
|
+
expect {RFlow::Message::Data.new()}.to raise_error(ArgumentError)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "if created with an invalid schema for the serialization" do
|
20
|
+
it "should throw and exception" do
|
21
|
+
expect {RFlow::Message::Data.new(@invalid_avro_schema_string)}.to raise_error(ArgumentError)
|
22
|
+
expect {RFlow::Message::Data.new(@invalid_avro_schema_string, 'avro')}.to raise_error(ArgumentError)
|
23
|
+
expect {RFlow::Message::Data.new(@invalid_avro_schema_string, 'avro')}.to raise_error(ArgumentError)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "if created with a valid avro schema and serialization" do
|
28
|
+
end
|
29
|
+
|
30
|
+
context "if created with a valid avro schema" do
|
31
|
+
it "should instantiate correctly" do
|
32
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'avro')}.to_not raise_error
|
33
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'avro')}.to_not raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
context "if created with a non-avro data serialization" do
|
37
|
+
it "should throw an exception" do
|
38
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'unknown')}.to raise_error(ArgumentError)
|
39
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, :unknown)}.to raise_error(ArgumentError)
|
40
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'xml')}.to raise_error(ArgumentError)
|
41
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, :xml)}.to raise_error(ArgumentError)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "if created with an avro serialization" do
|
46
|
+
it "should instantiate correctly" do
|
47
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'avro')}.to_not raise_error
|
48
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'avro')}.to_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
context "if created with a serialized data object" do
|
52
|
+
it "should instantiate correctly" do
|
53
|
+
expect {RFlow::Message::Data.new(@valid_avro_string_schema_string, 'avro', @avro_serialized_string)}.to_not raise_error
|
54
|
+
message = RFlow::Message::Data.new(@valid_avro_string_schema_string, 'avro', @avro_serialized_string)
|
55
|
+
p message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
|
5
|
+
require 'rflow/message'
|
6
|
+
|
7
|
+
describe RFlow::Message do
|
8
|
+
|
9
|
+
context "if created with an unknown data type" do
|
10
|
+
it "should throw an exception" do
|
11
|
+
expect {RFlow::Message.new('non_existant_data_type')}.to raise_error(ArgumentError)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
context "if created with a known data type" do
|
17
|
+
before(:all) do
|
18
|
+
@avro_string_schema_string = '{"type": "string"}'
|
19
|
+
RFlow::Configuration.add_available_data_type(:string_type, 'avro', @avro_string_schema_string)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should instantiate correctly" do
|
23
|
+
expect {RFlow::Message.new('string_type')}.to_not raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
context "if created with empty provenance" do
|
27
|
+
context "if created with an unknown data serialization" do
|
28
|
+
it "should throw an exception" do
|
29
|
+
expect {RFlow::Message.new('string_type', [], 'unknown')}.to raise_error(ArgumentError)
|
30
|
+
expect {RFlow::Message.new('string_type', [], :unknown)}.to raise_error(ArgumentError)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "if created with a known data serialization" do
|
35
|
+
it "should instantiate correctly" do
|
36
|
+
expect {RFlow::Message.new('string_type', [], 'avro')}.to_not raise_error
|
37
|
+
expect {RFlow::Message.new('string_type', [], 'avro')}.to_not raise_error
|
38
|
+
end
|
39
|
+
|
40
|
+
context "if created with a mismatched schema" do
|
41
|
+
end
|
42
|
+
|
43
|
+
context "if created with a matched schema" do
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
context "if created with a nil schema" do
|
48
|
+
context "if created with a serialized data object" do
|
49
|
+
before(:all) do
|
50
|
+
@string = 'this is a string to be serialized'
|
51
|
+
@avro_serialized_string = encode_avro(@avro_string_schema_string, @string)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should instantiate correctly" do
|
55
|
+
expect {RFlow::Message.new('string_type', [], 'avro', nil, @avro_serialized_string)}.to_not raise_error
|
56
|
+
message = RFlow::Message.new('string_type', [], 'avro', nil, @avro_serialized_string)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "if created with invalid provenance" do
|
64
|
+
before(:all) do
|
65
|
+
@invalid_processing_event_hash = {'started_at' => 'bad time string'}
|
66
|
+
@invalid_provenance = [@invalid_processing_event_hash]
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should throw an exception" do
|
70
|
+
expect {RFlow::Message.new('string_type', @invalid_provenance)}.to raise_error(ArgumentError)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "if created with valid provenance" do
|
75
|
+
before(:all) do
|
76
|
+
@valid_xmlschema_time = '2001-01-01T01:01:01.000001Z'
|
77
|
+
@valid_processing_event_hash = {'component_instance_uuid' => 'uuid', 'started_at' => @valid_xmlschema_time}
|
78
|
+
@valid_processing_event = RFlow::Message::ProcessingEvent.new('uuid', @valid_xmlschema_time, @valid_xmlschema_time, 'context')
|
79
|
+
@valid_provenance = [
|
80
|
+
RFlow::Message::ProcessingEvent.new('uuid'),
|
81
|
+
@valid_processing_event_hash,
|
82
|
+
@valid_processing_event,
|
83
|
+
]
|
84
|
+
@valid_provenance_hashes = [
|
85
|
+
{"component_instance_uuid"=>"uuid", "started_at"=>nil, "completed_at"=>nil, "context"=>nil},
|
86
|
+
{"component_instance_uuid"=>"uuid", "started_at"=>@valid_xmlschema_time, "completed_at"=>nil, "context"=>nil},
|
87
|
+
{"component_instance_uuid"=>"uuid", "started_at"=>@valid_xmlschema_time, "completed_at"=>@valid_xmlschema_time, "context"=>"context"},
|
88
|
+
]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should instantiate correctly" do
|
92
|
+
p @valid_provenance
|
93
|
+
expect {RFlow::Message.new('string_type', @valid_provenance)}.to_not raise_error
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should correctly set the provenance processing events" do
|
97
|
+
message = RFlow::Message.new('string_type', @valid_provenance)
|
98
|
+
message.provenance[1].component_instance_uuid.should == 'uuid'
|
99
|
+
message.provenance[1].started_at.should == Time.xmlschema(@valid_xmlschema_time)
|
100
|
+
message.provenance[1].completed_at.should == nil
|
101
|
+
message.provenance[1].context.should == nil
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should to_hash its provenance correctly" do
|
105
|
+
message = RFlow::Message.new('string_type', @valid_provenance)
|
106
|
+
message.provenance.map(&:to_hash).should == @valid_provenance_hashes
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
context "if correctly created" do
|
112
|
+
it "should serialize and deserialized correctly to/from avro" do
|
113
|
+
message = RFlow::Message.new('string_type')
|
114
|
+
message.provenance << RFlow::Message::ProcessingEvent.new('UUID')
|
115
|
+
message.data.data_object = 'teh awesome'
|
116
|
+
|
117
|
+
processed_message = RFlow::Message.from_avro(message.to_avro)
|
118
|
+
message.data.to_avro.should == processed_message.data.to_avro
|
119
|
+
message.data.data_object.should == processed_message.data.data_object
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context "if data extensions exist" do
|
124
|
+
it "should extend the data element with the extension" do
|
125
|
+
module ExtensionModule; def ext_method; end; end
|
126
|
+
|
127
|
+
message = RFlow::Message.new('string_type')
|
128
|
+
message.data.methods.should_not include(:ext_method)
|
129
|
+
|
130
|
+
RFlow::Configuration.add_available_data_extension('string_type', ExtensionModule)
|
131
|
+
message = RFlow::Message.new('string_type')
|
132
|
+
message.data.methods.should include(:ext_method)
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should correctly handle large raw types" do
|
139
|
+
message = RFlow::Message.new('RFlow::Message::Data::Raw')
|
140
|
+
message.data.raw = Array.new(101) { rand(256) }.pack('c*')
|
141
|
+
|
142
|
+
message_avro = message.to_avro.force_encoding('BINARY')
|
143
|
+
|
144
|
+
processed_message = RFlow::Message.from_avro(message_avro)
|
145
|
+
processed_message_avro = processed_message.to_avro.force_encoding('BINARY')
|
146
|
+
|
147
|
+
@raw_schema = RFlow::Configuration.available_data_types['RFlow::Message::Data::Raw']['avro']
|
148
|
+
|
149
|
+
encode_avro(@raw_schema, message.data.data_object).should == message.data.to_avro
|
150
|
+
decode_avro(@raw_schema, message.data.to_avro).should == message.data.data_object
|
151
|
+
|
152
|
+
p message.data.raw
|
153
|
+
p message_avro
|
154
|
+
p message_avro.bytesize
|
155
|
+
p processed_message_avro
|
156
|
+
p processed_message_avro.bytesize
|
157
|
+
|
158
|
+
p message_avro.encoding
|
159
|
+
p message_avro.valid_encoding?
|
160
|
+
|
161
|
+
p processed_message_avro.encoding
|
162
|
+
p processed_message_avro.valid_encoding?
|
163
|
+
|
164
|
+
message_data_avro = message.data.to_avro.force_encoding('BINARY')
|
165
|
+
processed_message_data_avro = processed_message.data.to_avro.force_encoding('BINARY')
|
166
|
+
|
167
|
+
p message_data_avro.encoding
|
168
|
+
p message_data_avro.valid_encoding?
|
169
|
+
p message_data_avro
|
170
|
+
p processed_message_data_avro.encoding
|
171
|
+
p processed_message_data_avro.valid_encoding?
|
172
|
+
p processed_message_data_avro
|
173
|
+
|
174
|
+
Digest::MD5.hexdigest(message_avro).should == Digest::MD5.hexdigest(processed_message_avro)
|
175
|
+
|
176
|
+
|
177
|
+
message_data_avro.should == processed_message_data_avro
|
178
|
+
Digest::MD5.hexdigest(message_data_avro).should == Digest::MD5.hexdigest(processed_message_data_avro)
|
179
|
+
Digest::MD5.hexdigest(message.data.raw).should == Digest::MD5.hexdigest(processed_message.data.raw)
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|