cranium 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +3 -0
- data/Vagrantfile +24 -0
- data/bin/cranium +9 -0
- data/config/cucumber.yml +9 -0
- data/cranium.gemspec +26 -0
- data/db/setup.sql +8 -0
- data/docker-compose.yml +8 -0
- data/examples/config.rb +14 -0
- data/examples/deduplication.rb +27 -0
- data/examples/import_csv_with_field_lookup_inserting_new_dimension_keys.rb +26 -0
- data/examples/incremental_extract.rb +17 -0
- data/examples/lookup_with_multiple_fields.rb +25 -0
- data/features/archive.feature +49 -0
- data/features/extract/incremental_extract.feature +56 -0
- data/features/extract/simple_extract.feature +85 -0
- data/features/import/import_csv_to_database_as_delta.feature +38 -0
- data/features/import/import_csv_to_database_with_delete_insert_merging.feature +51 -0
- data/features/import/import_csv_to_database_with_truncate_insert.feature +49 -0
- data/features/import/import_csv_to_database_with_update_merging.feature +46 -0
- data/features/import/import_csv_with_always_inserting_new_dimension_keys.feature +137 -0
- data/features/import/import_csv_with_field_lookup_inserting_new_dimension_keys.feature +62 -0
- data/features/import/import_csv_with_field_lookup_transformation.feature +125 -0
- data/features/import/import_csv_with_transformation.feature +55 -0
- data/features/import/import_multiple_csv_files_without_transformations.feature +44 -0
- data/features/import/import_with_load_id_from_sequence.feature +53 -0
- data/features/import/import_with_lookup_from_multiple_fields.feature +64 -0
- data/features/read.feature +56 -0
- data/features/remove.feature +44 -0
- data/features/restore_database_connection.feature +55 -0
- data/features/step_definitions/database_table_steps.rb +40 -0
- data/features/step_definitions/definition_steps.rb +3 -0
- data/features/step_definitions/execution_steps.rb +23 -0
- data/features/step_definitions/file_steps.rb +39 -0
- data/features/support/class_extensions.rb +24 -0
- data/features/support/env.rb +27 -0
- data/features/support/randomize.rb +22 -0
- data/features/support/stop_on_first_error.rb +5 -0
- data/features/transform/deduplication.feature +37 -0
- data/features/transform/empty_transformation.feature +72 -0
- data/features/transform/join.feature +180 -0
- data/features/transform/join_multiple_files_into_one_output_file.feature +46 -0
- data/features/transform/output_rows.feature +70 -0
- data/features/transform/projection.feature +34 -0
- data/features/transform/raw_ruby_transformation.feature +69 -0
- data/features/transform/split_field.feature +39 -0
- data/lib/cranium/application.rb +104 -0
- data/lib/cranium/archiver.rb +36 -0
- data/lib/cranium/attribute_dsl.rb +43 -0
- data/lib/cranium/command_line_options.rb +27 -0
- data/lib/cranium/configuration.rb +33 -0
- data/lib/cranium/data_importer.rb +35 -0
- data/lib/cranium/data_reader.rb +48 -0
- data/lib/cranium/data_transformer.rb +126 -0
- data/lib/cranium/database.rb +36 -0
- data/lib/cranium/definition_registry.rb +21 -0
- data/lib/cranium/dimension_manager.rb +65 -0
- data/lib/cranium/dsl/database_definition.rb +23 -0
- data/lib/cranium/dsl/extract_definition.rb +28 -0
- data/lib/cranium/dsl/import_definition.rb +50 -0
- data/lib/cranium/dsl/source_definition.rb +67 -0
- data/lib/cranium/dsl.rb +100 -0
- data/lib/cranium/extensions/file.rb +7 -0
- data/lib/cranium/extensions/sequel_greenplum.rb +30 -0
- data/lib/cranium/external_table.rb +75 -0
- data/lib/cranium/extract/data_extractor.rb +11 -0
- data/lib/cranium/extract/storage.rb +57 -0
- data/lib/cranium/extract/strategy/base.rb +27 -0
- data/lib/cranium/extract/strategy/incremental.rb +16 -0
- data/lib/cranium/extract/strategy/simple.rb +9 -0
- data/lib/cranium/extract/strategy.rb +7 -0
- data/lib/cranium/extract.rb +7 -0
- data/lib/cranium/import_strategy/base.rb +55 -0
- data/lib/cranium/import_strategy/delete_insert.rb +40 -0
- data/lib/cranium/import_strategy/delta.rb +8 -0
- data/lib/cranium/import_strategy/merge.rb +50 -0
- data/lib/cranium/import_strategy/truncate_insert.rb +19 -0
- data/lib/cranium/import_strategy.rb +9 -0
- data/lib/cranium/logging.rb +15 -0
- data/lib/cranium/profiling.rb +13 -0
- data/lib/cranium/progress_output.rb +37 -0
- data/lib/cranium/sequel/hash.rb +32 -0
- data/lib/cranium/sequel.rb +5 -0
- data/lib/cranium/source_registry.rb +21 -0
- data/lib/cranium/test_framework/cucumber_table.rb +140 -0
- data/lib/cranium/test_framework/database_entity.rb +29 -0
- data/lib/cranium/test_framework/database_sequence.rb +16 -0
- data/lib/cranium/test_framework/database_table.rb +33 -0
- data/lib/cranium/test_framework/upload_directory.rb +39 -0
- data/lib/cranium/test_framework/world.rb +66 -0
- data/lib/cranium/test_framework.rb +10 -0
- data/lib/cranium/transformation/duplication_index.rb +42 -0
- data/lib/cranium/transformation/index.rb +83 -0
- data/lib/cranium/transformation/join.rb +141 -0
- data/lib/cranium/transformation/sequence.rb +42 -0
- data/lib/cranium/transformation.rb +8 -0
- data/lib/cranium/transformation_record.rb +45 -0
- data/lib/cranium.rb +57 -0
- data/rake/test.rake +31 -0
- data/spec/cranium/application_spec.rb +166 -0
- data/spec/cranium/archiver_spec.rb +44 -0
- data/spec/cranium/command_line_options_spec.rb +32 -0
- data/spec/cranium/configuration_spec.rb +31 -0
- data/spec/cranium/data_importer_spec.rb +55 -0
- data/spec/cranium/data_transformer_spec.rb +16 -0
- data/spec/cranium/database_spec.rb +69 -0
- data/spec/cranium/definition_registry_spec.rb +45 -0
- data/spec/cranium/dimension_manager_spec.rb +63 -0
- data/spec/cranium/dsl/database_definition_spec.rb +23 -0
- data/spec/cranium/dsl/extract_definition_spec.rb +76 -0
- data/spec/cranium/dsl/import_definition_spec.rb +153 -0
- data/spec/cranium/dsl/source_definition_spec.rb +84 -0
- data/spec/cranium/dsl_spec.rb +119 -0
- data/spec/cranium/external_table_spec.rb +71 -0
- data/spec/cranium/extract/storage_spec.rb +125 -0
- data/spec/cranium/logging_spec.rb +37 -0
- data/spec/cranium/sequel/hash_spec.rb +56 -0
- data/spec/cranium/source_registry_spec.rb +31 -0
- data/spec/cranium/test_framework/cucumber_table_spec.rb +144 -0
- data/spec/cranium/transformation/duplication_index_spec.rb +75 -0
- data/spec/cranium/transformation/index_spec.rb +178 -0
- data/spec/cranium/transformation/join_spec.rb +43 -0
- data/spec/cranium/transformation/sequence_spec.rb +83 -0
- data/spec/cranium/transformation_record_spec.rb +78 -0
- data/spec/cranium_spec.rb +53 -0
- data/spec/spec_helper.rb +1 -0
- metadata +362 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe Cranium::Transformation::Index do
|
4
|
+
|
5
|
+
let(:index) { Cranium::Transformation::Index.new }
|
6
|
+
let(:connection) { double "Greenplum connection" }
|
7
|
+
let(:dimension_manager) { double "DimensionManager" }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
allow(Cranium::Database).to receive(:connection).and_return(connection)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
def stub_cache_query(table_name, key_fields, value_field, result)
|
16
|
+
allow(dimension_manager).to receive(:create_cache_for_field).with(value_field).and_return(result)
|
17
|
+
allow(Cranium::DimensionManager).to receive(:for).with(table_name, key_fields).and_return(dimension_manager)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
describe "#lookup" do
|
23
|
+
context "the first time it's called" do
|
24
|
+
it "should query the requested key value from the database" do
|
25
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 1",
|
26
|
+
[2345] => "contact 2",
|
27
|
+
[3456] => "contact 3"}
|
28
|
+
|
29
|
+
expect(index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 2345)).to eq("contact 2")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should query the requested multi-key value from the database" do
|
33
|
+
stub_cache_query :dim_contact, [:key_1, :key_2], :contact_key, {[12, 34] => "contact 1",
|
34
|
+
[23, 45] => "contact 2",
|
35
|
+
[34, 56] => "contact 3"}
|
36
|
+
|
37
|
+
expect(index.lookup(:contact_key, from_table: :dim_contact, match: {key_1: 23, key_2: 45})).to eq("contact 2")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
context "on subsequent calls" do
|
43
|
+
it "should look up the requested value from an internal cache" do
|
44
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 1"}
|
45
|
+
index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 1234)
|
46
|
+
|
47
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 2"}
|
48
|
+
expect(index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 1234)).to eq("contact 1")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
it "should return :not_found if the key value was not found" do
|
54
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact 2"}
|
55
|
+
|
56
|
+
expect(index.lookup(:contact_key, from_table: :dim_contact, match_column: :customer_id, to_value: 2345)).to eq(:not_found)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
it "should raise an error if both :if_not_found_then_insert and :if_not_found_then are specified" do
|
61
|
+
expect do
|
62
|
+
index.lookup(:contact_key, if_not_found_then: -1, if_not_found_then_insert: {})
|
63
|
+
end.to raise_error ArgumentError, "Cannot specify both :if_not_found_then and :if_not_found_then_insert options"
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
context "when :if_not_found_then is specified" do
|
68
|
+
it "should return the specified value if the lookup failed" do
|
69
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact"}
|
70
|
+
|
71
|
+
expect(index.lookup(:contact_key,
|
72
|
+
from_table: :dim_contact,
|
73
|
+
match_column: :customer_id,
|
74
|
+
to_value: 2345,
|
75
|
+
if_not_found_then: -1)).to eq(-1)
|
76
|
+
end
|
77
|
+
|
78
|
+
context "when the specified value is a lamba expression" do
|
79
|
+
it "should evaluate the expression and return its value if the lookup failed" do
|
80
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact"}
|
81
|
+
|
82
|
+
expect(index.lookup(:contact_key,
|
83
|
+
from_table: :dim_contact,
|
84
|
+
match_column: :customer_id,
|
85
|
+
to_value: 2345,
|
86
|
+
if_not_found_then: -> { -1 })).to eq(-1)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
context "when :if_not_found_then_insert is specified" do
|
93
|
+
|
94
|
+
before(:each) do
|
95
|
+
stub_cache_query :dim_contact, [:customer_id], :contact_key, {[1234] => "contact"}
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when a single key is used" do
|
99
|
+
it "should insert a new record into the specified table" do
|
100
|
+
expect(dimension_manager).to receive(:insert).with(:contact_key, {contact_key: 1, customer_id: 2345})
|
101
|
+
|
102
|
+
index.lookup :contact_key,
|
103
|
+
from_table: :dim_contact,
|
104
|
+
match_column: :customer_id,
|
105
|
+
to_value: 2345,
|
106
|
+
if_not_found_then_insert: {contact_key: 1, customer_id: 2345}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "when multiple keys are used" do
|
111
|
+
it "should insert a new record into the specified table" do
|
112
|
+
stub_cache_query :dim_contact, [:key_1, :key_2], :contact_key, {[12, 34] => "contact"}
|
113
|
+
|
114
|
+
expect(dimension_manager).to receive(:insert).with(:contact_key, contact_key: 1, key_1: 23, key_2: 45)
|
115
|
+
|
116
|
+
index.lookup :contact_key,
|
117
|
+
from_table: :dim_contact,
|
118
|
+
match: {key_1: 23, key_2: 45},
|
119
|
+
if_not_found_then_insert: {contact_key: 1, key_1: 23, key_2: 45}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should fill out the new record's lookup key automatically" do
|
124
|
+
expect(dimension_manager).to receive(:insert).with(:contact_key, name: "new contact", customer_id: 2345)
|
125
|
+
|
126
|
+
index.lookup :contact_key,
|
127
|
+
from_table: :dim_contact,
|
128
|
+
match_column: :customer_id,
|
129
|
+
to_value: 2345,
|
130
|
+
if_not_found_then_insert: {name: "new contact"}
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should overwrite the new record's lookup key if specified" do
|
134
|
+
expect(dimension_manager).to receive(:insert).with(:contact_key, customer_id: 2345)
|
135
|
+
|
136
|
+
index.lookup :contact_key,
|
137
|
+
from_table: :dim_contact,
|
138
|
+
match_column: :customer_id,
|
139
|
+
to_value: 2345,
|
140
|
+
if_not_found_then_insert: {customer_id: 4567}
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should return the new record's lookup value" do
|
144
|
+
allow(dimension_manager).to receive_messages insert: 98765
|
145
|
+
|
146
|
+
expect(index.lookup(:contact_key,
|
147
|
+
from_table: :dim_contact,
|
148
|
+
match_column: :customer_id,
|
149
|
+
to_value: 2345,
|
150
|
+
if_not_found_then_insert: {contact_key: 98765})).to eq(98765)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
describe "#insert" do
|
157
|
+
before(:each) do
|
158
|
+
stub_cache_query :dim_contact, [:contact_key], :contact_key, {[1234] => "contact"}
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should insert a new record into the specified table" do
|
162
|
+
expect(dimension_manager).to receive(:insert).with(:contact_key, {contact_key: 1, customer_id: 2345})
|
163
|
+
|
164
|
+
index.insert :contact_key,
|
165
|
+
table: :dim_contact,
|
166
|
+
record: {contact_key: 1, customer_id: 2345}
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should return the new record's lookup value" do
|
170
|
+
allow(dimension_manager).to receive_messages insert: 98765
|
171
|
+
|
172
|
+
expect(index.insert :contact_key,
|
173
|
+
table: :dim_contact,
|
174
|
+
record: {contact_key: 98765}).to eq(98765)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe Cranium::Transformation::Join do
|
4
|
+
|
5
|
+
let(:join) { Cranium::Transformation::Join.new }
|
6
|
+
|
7
|
+
describe "#execute" do
|
8
|
+
context "when validating its parameters" do
|
9
|
+
before(:each) do
|
10
|
+
join.source_left = "left source"
|
11
|
+
join.source_right = "right source"
|
12
|
+
join.target = "target source"
|
13
|
+
join.match_fields = { field1: :field2 }
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should raise an error if :source_left isn't set" do
|
17
|
+
join.source_left = nil
|
18
|
+
expect { join.execute }.to raise_error "Missing left source for join transformation"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an error if :source_right isn't set" do
|
22
|
+
join.source_right = nil
|
23
|
+
expect { join.execute }.to raise_error "Missing right source for join transformation"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should raise an error if :target isn't set" do
|
27
|
+
join.target = nil
|
28
|
+
expect { join.execute }.to raise_error "Missing target for join transformation"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should raise an error if :match_fields is set but isn't a Hash" do
|
32
|
+
join.match_fields = :field
|
33
|
+
expect { join.execute }.to raise_error "Invalid match fields for join transformation"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise an error if :type is not supported" do
|
37
|
+
join.type = :cross
|
38
|
+
expect { join.execute }.to raise_error "Invalid type for join transformation"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe Cranium::Transformation::Sequence do
|
4
|
+
|
5
|
+
def stub_next_value(value)
|
6
|
+
dataset = double "dataset"
|
7
|
+
allow(dataset).to receive_messages first: { next_value: value }
|
8
|
+
allow(Cranium::Database).to receive_message_chain(:connection, :[]).with("SELECT nextval('id_seq') AS next_value").and_return(dataset)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
let(:sequence) { Cranium::Transformation::Sequence.new :id_seq }
|
14
|
+
|
15
|
+
describe ".by_name" do
|
16
|
+
before(:each) { Cranium::Transformation::Sequence.instance_variable_set :@sequences, nil }
|
17
|
+
|
18
|
+
it "should return a sequence with the specified name" do
|
19
|
+
sequence = Cranium::Transformation::Sequence.by_name(:id_seq)
|
20
|
+
|
21
|
+
expect(sequence).to be_a Cranium::Transformation::Sequence
|
22
|
+
expect(sequence.name).to eq(:id_seq)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should schedule a newly created sequence's flush method as an after_import hook" do
|
26
|
+
expect(Cranium.application).to receive(:after_import).once
|
27
|
+
|
28
|
+
Cranium::Transformation::Sequence.by_name(:id_seq)
|
29
|
+
Cranium::Transformation::Sequence.by_name(:id_seq)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should memoize previously created instances" do
|
33
|
+
expect(Cranium::Transformation::Sequence.by_name(:id_seq)).to equal Cranium::Transformation::Sequence.by_name(:id_seq)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
describe "#next_value" do
|
39
|
+
before(:each) do
|
40
|
+
stub_next_value 123
|
41
|
+
end
|
42
|
+
|
43
|
+
context "the first time it's called" do
|
44
|
+
it "should return the named sequence's next value read from the database" do
|
45
|
+
expect(sequence.next_value).to eq(123)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "on subsequent calls" do
|
50
|
+
it "should increment its counter internally without querying the database" do
|
51
|
+
expect(sequence.next_value).to eq(123)
|
52
|
+
|
53
|
+
expect(Cranium::Database).not_to receive :connection
|
54
|
+
|
55
|
+
expect(sequence.next_value).to eq(124)
|
56
|
+
expect(sequence.next_value).to eq(125)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
describe "#flush" do
|
63
|
+
let(:sequence) { Cranium::Transformation::Sequence.new :id_seq }
|
64
|
+
|
65
|
+
it "should not use the database if no value was ever requested from the sequence" do
|
66
|
+
expect(Cranium::Database).not_to receive :connection
|
67
|
+
|
68
|
+
sequence.flush
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should set the database sequence's value to the last value returned" do
|
72
|
+
stub_next_value 123
|
73
|
+
sequence.next_value
|
74
|
+
|
75
|
+
connection = double "connection"
|
76
|
+
allow(Cranium::Database).to receive_messages connection: connection
|
77
|
+
expect(connection).to receive(:run).with("SELECT setval('id_seq', 123)")
|
78
|
+
|
79
|
+
sequence.flush
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
|
3
|
+
describe Cranium::TransformationRecord do
|
4
|
+
|
5
|
+
let(:record) { Cranium::TransformationRecord.new [:field1, :field2, :field3], [:field1, :field2, :field3] }
|
6
|
+
|
7
|
+
describe "#input_data=" do
|
8
|
+
it "should set the input data row" do
|
9
|
+
record.input_data = ["one", "three", "five"]
|
10
|
+
expect(record.data).to eq({ :field1 => "one", :field2 => "three", :field3 => "five" })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
describe "#[]" do
|
16
|
+
it "should access the fields of the record as if it were a Hash" do
|
17
|
+
record.input_data = ["one", "two", "three"]
|
18
|
+
expect(record[:field2]).to eq("two")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
describe "#[]=" do
|
24
|
+
it "should set the fields of the record as if it were a Hash" do
|
25
|
+
record.input_data = ["one", "two", "three"]
|
26
|
+
record[:field2] = "four"
|
27
|
+
expect(record[:field2]).to eq("four")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
describe "#split_field" do
|
33
|
+
|
34
|
+
let(:record) { Cranium::TransformationRecord.new [:source_field], [:target_field1, :target_field2] }
|
35
|
+
|
36
|
+
it "should store values into respective fields and drop extra values" do
|
37
|
+
record.input_data = ["first|second|third"]
|
38
|
+
record.split_field :source_field, into: [:target_field1, :target_field2], by: "|"
|
39
|
+
expect(record[:target_field1]).to eq("first")
|
40
|
+
expect(record[:target_field2]).to eq("second")
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when default value is not set" do
|
44
|
+
it "should repeat last value when there are not enough values" do
|
45
|
+
record.input_data = ["first"]
|
46
|
+
record.split_field :source_field, into: [:target_field1, :target_field2], by: "|"
|
47
|
+
expect(record[:target_field1]).to eq("first")
|
48
|
+
expect(record[:target_field2]).to eq("first")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when default value is specified" do
|
53
|
+
it "should use default value when there are not enough values" do
|
54
|
+
record.input_data = ["first"]
|
55
|
+
record.split_field :source_field, into: [:target_field1, :target_field2], by: "|", default_value: "--"
|
56
|
+
expect(record[:target_field1]).to eq("first")
|
57
|
+
expect(record[:target_field2]).to eq("--")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
describe "#has_key?" do
|
65
|
+
it "should return true if the record contains data for the specified key" do
|
66
|
+
record.input_data = ["one", "two", "three"]
|
67
|
+
|
68
|
+
expect(record.has_key?(:field1)).to be_truthy
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return false if the record doesn't contain data for the specified key" do
|
72
|
+
record.input_data = ["one", "two", "three"]
|
73
|
+
|
74
|
+
expect(record.has_key?(:field4)).to be_falsey
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Cranium do
|
4
|
+
|
5
|
+
describe ".application" do
|
6
|
+
it "should return an Application object" do
|
7
|
+
expect(Cranium.application).to be_a Cranium::Application
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return a singleton" do
|
11
|
+
expect(Cranium.application).to equal Cranium.application
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
describe ".configure" do
|
17
|
+
it "should set or modify the existing configuration" do
|
18
|
+
Cranium.configure do |config|
|
19
|
+
config.greenplum_connection_string = "greenplum connection"
|
20
|
+
config.mysql_connection_string = "mysql connection"
|
21
|
+
end
|
22
|
+
|
23
|
+
Cranium.configure do |config|
|
24
|
+
config.greenplum_connection_string = "new greenplum connection"
|
25
|
+
end
|
26
|
+
|
27
|
+
expect(Cranium.configuration.greenplum_connection_string).to eq("new greenplum connection")
|
28
|
+
expect(Cranium.configuration.mysql_connection_string).to eq("mysql connection")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
describe ".configuration" do
|
34
|
+
it "should return the configuration" do
|
35
|
+
expect(Cranium.configuration).to be_a Cranium::Configuration
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not let the user modify the configuration" do
|
39
|
+
expect { Cranium.configuration.greenplum_connection_string = "constring" }.to raise_error(RuntimeError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
describe ".load_arguments" do
|
45
|
+
it "should return the load arguments of the application" do
|
46
|
+
app = double "application", load_arguments: "load_arguments"
|
47
|
+
allow(Cranium).to receive(:application).and_return(app)
|
48
|
+
|
49
|
+
expect(Cranium.load_arguments).to eq "load_arguments"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../lib/cranium'
|