rspec-hive 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.rubocop.yml +13 -1
- data/.rubocop_u2i.yml +9 -1
- data/.travis.yml +19 -0
- data/Guardfile +12 -1
- data/README.md +3 -1
- data/Rakefile +11 -2
- data/examples/{query.rb → lib/query.rb} +2 -5
- data/examples/{hive_tests_config.yml.example → rspec-hive.yml.example} +0 -0
- data/examples/spec/query_spec.rb +103 -0
- data/examples/spec/spec_helper.rb +22 -0
- data/lib/rspec/hive.rb +7 -2
- data/lib/rspec/hive/connection_delegator.rb +17 -5
- data/lib/rspec/hive/connector.rb +0 -1
- data/lib/rspec/hive/exponential_backoff.rb +15 -0
- data/lib/rspec/hive/matchers.rb +29 -0
- data/lib/rspec/hive/query_builder.rb +83 -0
- data/lib/rspec/hive/query_builder/null_strategy.rb +11 -0
- data/lib/rspec/hive/query_builder/row_transformer.rb +63 -0
- data/lib/rspec/hive/query_builder/type_faker.rb +36 -0
- data/lib/rspec/hive/query_builder/value_by_type_strategy.rb +13 -0
- data/lib/rspec/hive/query_builder_helper.rb +24 -0
- data/lib/rspec/{rake_tasks → hive}/railtie.rb +2 -2
- data/lib/rspec/{rake_tasks → hive/rake_tasks}/docker.rake +0 -0
- data/lib/rspec/hive/version.rb +1 -1
- data/lib/rspec/hive/with_hive_connection.rb +16 -10
- data/rspec-hive.gemspec +6 -4
- data/spec/.rubocop.yml +4 -0
- data/spec/lib/rspec/hive/configuration_spec.rb +9 -6
- data/spec/lib/rspec/hive/connection_delegator_spec.rb +1 -1
- data/spec/lib/rspec/hive/connector_spec.rb +1 -1
- data/spec/lib/rspec/hive/db_name_spec.rb +1 -1
- data/spec/lib/rspec/hive/matchers_spec.rb +94 -0
- data/spec/lib/rspec/hive/query_builder/row_transformer_spec.rb +37 -0
- data/spec/lib/rspec/hive/query_builder_spec.rb +143 -0
- data/spec/lib/rspec/hive_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -62
- metadata +68 -24
- data/examples/config_helper.rb +0 -1
- data/examples/query_spec.rb +0 -41
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative 'type_faker'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Hive
|
5
|
+
class QueryBuilder
|
6
|
+
class RowTransformer
|
7
|
+
def initialize(schema, missing_column_strategy)
|
8
|
+
@schema = schema
|
9
|
+
@strategy = missing_column_strategy
|
10
|
+
end
|
11
|
+
|
12
|
+
def transform(row)
|
13
|
+
if row.respond_to?(:each_pair)
|
14
|
+
mock_hive_row(row)
|
15
|
+
elsif row.respond_to?(:each)
|
16
|
+
array_row(row)
|
17
|
+
else
|
18
|
+
raise ArgumentError, 'Array or Hash required!'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :schema, :strategy
|
25
|
+
|
26
|
+
HIVE_NIL = '\N'.freeze
|
27
|
+
|
28
|
+
def array_row(row)
|
29
|
+
size = schema.columns.size
|
30
|
+
missing = size - row.size
|
31
|
+
if missing > 0
|
32
|
+
row_with_missing_columns(row)
|
33
|
+
else
|
34
|
+
row
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def row_with_missing_columns(row)
|
39
|
+
schema.columns.map.with_index do |column, index|
|
40
|
+
if index > row.size
|
41
|
+
strategy.missing(column)
|
42
|
+
else
|
43
|
+
row[index]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def mock_hive_row(partial_row)
|
49
|
+
symbolized_row = Hash[partial_row.map { |k, v| [k.to_sym, v] }]
|
50
|
+
|
51
|
+
schema.columns.map do |column|
|
52
|
+
value = symbolized_row.fetch(column.name.to_sym) { strategy.missing(column) }
|
53
|
+
nil_to_null(value)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def nil_to_null(value)
|
58
|
+
value.nil? ? HIVE_NIL : value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'faker'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Hive
|
5
|
+
class QueryBuilder
|
6
|
+
class TypeFaker
|
7
|
+
class << self
|
8
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
9
|
+
def fake(type)
|
10
|
+
case type
|
11
|
+
when :int
|
12
|
+
Faker::Number.number(9)
|
13
|
+
when :smallint
|
14
|
+
Faker::Number.number(4)
|
15
|
+
when :tinyint
|
16
|
+
Faker::Number.number(1)
|
17
|
+
when :bigint
|
18
|
+
Faker::Number.number(12)
|
19
|
+
when :float
|
20
|
+
Faker::Number.decimal(4, 4)
|
21
|
+
when :double
|
22
|
+
Faker::Number.decimal(8, 8)
|
23
|
+
when :boolean
|
24
|
+
Faker::Boolean.boolean
|
25
|
+
when :string
|
26
|
+
Faker::Lorem.word
|
27
|
+
else
|
28
|
+
raise ArgumentError, "Unsupported type: #{type}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative 'query_builder'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Hive
|
5
|
+
module QueryBuilderHelper
|
6
|
+
def into_hive(schema)
|
7
|
+
hive_connection_guard!
|
8
|
+
::RSpec::Hive::QueryBuilder.new(schema, connection)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def hive_connection_present?
|
14
|
+
respond_to?(:connection) &&
|
15
|
+
(connection.is_a?(RBHive::TCLIConnection) ||
|
16
|
+
connection.is_a?(RSpec::Hive::ConnectionDelegator))
|
17
|
+
end
|
18
|
+
|
19
|
+
def hive_connection_guard!
|
20
|
+
raise 'Include WithHiveConnection' unless hive_connection_present?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
File without changes
|
data/lib/rspec/hive/version.rb
CHANGED
@@ -1,17 +1,13 @@
|
|
1
|
+
require_relative 'exponential_backoff'
|
2
|
+
|
1
3
|
module RSpec
|
2
4
|
module Hive
|
3
5
|
module WithHiveConnection
|
4
|
-
def hive
|
5
|
-
Hive.connector
|
6
|
-
end
|
7
|
-
|
8
|
-
def connection
|
9
|
-
@connection ||= hive.start_connection
|
10
|
-
end
|
11
|
-
|
12
6
|
def self.included(mod)
|
13
7
|
mod.before(:all) do
|
14
|
-
|
8
|
+
ExponentialBackoff.retryable(on: Thrift::TransportException) do
|
9
|
+
connection
|
10
|
+
end
|
15
11
|
end
|
16
12
|
|
17
13
|
mod.before(:each) do
|
@@ -19,9 +15,19 @@ module RSpec
|
|
19
15
|
end
|
20
16
|
|
21
17
|
mod.after(:all) do
|
22
|
-
|
18
|
+
hive_connector.stop_connection(connection) if hive_connector && @connection
|
23
19
|
end
|
24
20
|
end
|
21
|
+
|
22
|
+
def connection
|
23
|
+
@connection ||= hive_connector.start_connection
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def hive_connector
|
29
|
+
::RSpec::Hive.connector
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
data/rspec-hive.gemspec
CHANGED
@@ -21,13 +21,15 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_dependency 'rake', '~> 10.0'
|
23
23
|
spec.add_dependency 'colorize', '~> 0.7'
|
24
|
+
spec.add_dependency 'faker', '~> 1.6'
|
25
|
+
spec.add_dependency 'retryable', '~> 2.0.3'
|
26
|
+
spec.add_dependency 'rspec', '~> 3.4'
|
27
|
+
spec.add_dependency 'rbhive-u2i', '~> 1.0.0'
|
24
28
|
|
25
29
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
26
|
-
spec.add_development_dependency 'rspec', '~> 3.4'
|
27
30
|
spec.add_development_dependency 'rspec-its', '~> 1.2'
|
28
|
-
spec.add_development_dependency '
|
29
|
-
spec.add_development_dependency 'rubocop', '~>
|
30
|
-
spec.add_development_dependency 'rubocop-rspec', '~> 1.3'
|
31
|
+
spec.add_development_dependency 'rubocop', '~> 0.39'
|
32
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.4'
|
31
33
|
spec.add_development_dependency 'guard', '~> 2.6'
|
32
34
|
spec.add_development_dependency 'guard-rspec', '~> 4.3'
|
33
35
|
spec.add_development_dependency 'guard-rubocop', '~> 1.2'
|
data/spec/.rubocop.yml
ADDED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'tempfile'
|
3
3
|
|
4
|
-
describe RSpec::Hive::Configuration do
|
4
|
+
RSpec.describe RSpec::Hive::Configuration do
|
5
5
|
RSpec.shared_examples('config') do
|
6
6
|
its(:host) do
|
7
7
|
is_expected.to eq(expected_host)
|
@@ -53,20 +53,21 @@ describe RSpec::Hive::Configuration do
|
|
53
53
|
|
54
54
|
context 'when no configuration file is provided' do
|
55
55
|
let(:expected_port) { 10000 }
|
56
|
+
let!(:original_host_os) { RbConfig::CONFIG['host_os'] }
|
56
57
|
|
57
58
|
before { allow(Dir).to receive(:mktmpdir) { mock_tmpdir } }
|
58
59
|
|
59
|
-
subject { described_class.new }
|
60
|
-
|
61
60
|
context 'when on Mac' do
|
62
61
|
let(:mock_tmpdir) { '/Users/Shared/test/' }
|
63
62
|
let(:expected_host) { '192.168.99.100' }
|
64
63
|
let(:expected_host_shared_directory_path) { '/Users/Shared/test/spec-tmp-files' }
|
65
64
|
|
66
65
|
before do
|
67
|
-
|
66
|
+
RbConfig::CONFIG['host_os'] = 'mac os'
|
68
67
|
end
|
69
68
|
|
69
|
+
after { RbConfig::CONFIG['host_os'] = original_host_os }
|
70
|
+
|
70
71
|
include_examples('config')
|
71
72
|
end
|
72
73
|
|
@@ -76,9 +77,11 @@ describe RSpec::Hive::Configuration do
|
|
76
77
|
let(:expected_host_shared_directory_path) { '/tmp/test/spec-tmp-files' }
|
77
78
|
|
78
79
|
before do
|
79
|
-
|
80
|
+
RbConfig::CONFIG['host_os'] = 'linux'
|
80
81
|
end
|
81
82
|
|
83
|
+
after { RbConfig::CONFIG['host_os'] = original_host_os }
|
84
|
+
|
82
85
|
include_examples('config')
|
83
86
|
end
|
84
87
|
end
|
@@ -136,7 +139,7 @@ describe RSpec::Hive::Configuration do
|
|
136
139
|
include_examples('config')
|
137
140
|
end
|
138
141
|
|
139
|
-
context 'where there are some
|
142
|
+
context 'where there are some parameters required and optional' do
|
140
143
|
let(:yaml_hash) do
|
141
144
|
{
|
142
145
|
'hive' =>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe RSpec::Hive::Connector do
|
3
|
+
RSpec.describe RSpec::Hive::Connector do
|
4
4
|
describe '#start_connection' do
|
5
5
|
let(:tcli_connection) { double(RBHive::TCLIConnection) }
|
6
6
|
let(:connection_delegator) { double(RSpec::Hive::ConnectionDelegator) }
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'rspec/hive/query_builder_helper'
|
3
|
+
|
4
|
+
RSpec.describe 'match_result_set' do
|
5
|
+
include RSpec::Hive::QueryBuilderHelper
|
6
|
+
|
7
|
+
let(:john) { {first_name: 'John', last_name: 'Lennon', age: 40} }
|
8
|
+
let(:paul) { {first_name: 'Paul', last_name: 'McCartney', age: 73} }
|
9
|
+
|
10
|
+
let(:full_match) { expect(actual_rows).to match_result_set(expected_rows) }
|
11
|
+
let(:partial_match) { expect(actual_rows).to match_result_set(expected_rows).partially }
|
12
|
+
let(:full_match_fails) { expect(actual_rows).not_to match_result_set(expected_rows) }
|
13
|
+
let(:partial_match_fails) { expect(actual_rows).not_to match_result_set(expected_rows).partially }
|
14
|
+
|
15
|
+
context 'when the expected set has only one row' do
|
16
|
+
context 'but the actual set has more rows' do
|
17
|
+
let(:actual_rows) { [john, paul] }
|
18
|
+
|
19
|
+
context 'when the row is given as an array' do
|
20
|
+
let(:expected_rows) { [john.values] }
|
21
|
+
|
22
|
+
specify { full_match_fails }
|
23
|
+
specify { partial_match_fails }
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when the row is given as a hash' do
|
27
|
+
let(:expected_rows) { [john] }
|
28
|
+
|
29
|
+
specify { full_match_fails }
|
30
|
+
specify { partial_match_fails }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'and the actual set has one row' do
|
35
|
+
let(:actual_rows) { [john] }
|
36
|
+
|
37
|
+
context 'when the row is given as an array' do
|
38
|
+
context 'when the number of columns differs' do
|
39
|
+
let(:expected_rows) { [john.values << 'yoko'] }
|
40
|
+
|
41
|
+
specify { full_match_fails }
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when the actual and expected have are different' do
|
45
|
+
let(:expected_rows) { [paul.values] }
|
46
|
+
|
47
|
+
specify { full_match_fails }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'when the actual and expected rows are equal' do
|
51
|
+
let(:expected_rows) { [john.values] }
|
52
|
+
|
53
|
+
specify { full_match }
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'when the actual and expected rows are equal with rspec matchers' do
|
57
|
+
let(:expected_rows) { [[a_string_matching('John'), a_string_matching(/lennon/i), 40]] }
|
58
|
+
|
59
|
+
specify { full_match }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when the row is given as a hash' do
|
64
|
+
context 'when the number of columns differs' do
|
65
|
+
let(:expected_rows) { [john.dup.tap { |j| j[:ono] = 'yoko' }] }
|
66
|
+
|
67
|
+
specify { full_match_fails }
|
68
|
+
specify { partial_match_fails }
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the actual and expected have are different' do
|
72
|
+
let(:expected_rows) { [john.dup.tap { |j| j[:first_name] = 'yoko' }] }
|
73
|
+
|
74
|
+
specify { full_match_fails }
|
75
|
+
specify { partial_match_fails }
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'when the actual and expected rows are equal' do
|
79
|
+
let(:expected_rows) { [john] }
|
80
|
+
|
81
|
+
specify { full_match }
|
82
|
+
specify { partial_match }
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when matching a subset of columns' do
|
86
|
+
let(:expected_rows) { [{first_name: john[:first_name]}] }
|
87
|
+
|
88
|
+
specify { full_match_fails }
|
89
|
+
specify { partial_match }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RSpec::Hive::QueryBuilder::RowTransformer do
|
4
|
+
let(:transformer) { described_class.new(schema, missing_column_strategy) }
|
5
|
+
let(:schema) do
|
6
|
+
RBHive::TableSchema.new('table_name', nil) do
|
7
|
+
column :col1, :string
|
8
|
+
column :col2, :string
|
9
|
+
end
|
10
|
+
end
|
11
|
+
let(:column) { schema.instance_variable_get(:@columns).last }
|
12
|
+
let(:partition) { double }
|
13
|
+
let(:missing_column_strategy) { double }
|
14
|
+
|
15
|
+
describe '#transform' do
|
16
|
+
subject { transformer.transform(row) }
|
17
|
+
|
18
|
+
let(:row) { {col1: real_value} }
|
19
|
+
let(:real_value) { 'col1' }
|
20
|
+
let(:fake_value) { 'lorem' }
|
21
|
+
let(:expected_row) { [real_value, fake_value] }
|
22
|
+
|
23
|
+
before { allow(missing_column_strategy).to receive(:missing).with(column).and_return(fake_value) }
|
24
|
+
|
25
|
+
it 'fills missing fields' do
|
26
|
+
expect(subject[1]).to eq(fake_value)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'uses defined fields' do
|
30
|
+
expect(subject[0]).to eq(real_value)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'returns valid Rows' do
|
34
|
+
expect(subject).to eq(expected_row)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|