data_verifier 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +92 -0
- data/lib/data_verifier/baseline_builder.rb +28 -16
- data/lib/data_verifier/validator.rb +70 -42
- data/lib/data_verifier/version.rb +1 -1
- data/spec/lib/data_verifier/baseline_builder_spec.rb +50 -0
- data/spec/lib/data_verifier/validator_spec.rb +44 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f8aaa56a85ac1b493591067a74994a348f336b20b541149951d1fb61abcb5bf
|
4
|
+
data.tar.gz: ee108239cb4359371ba74eb6b7ad0bf3a29ee353e65cc718578da49ab9e32da0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f96afe9be08894e1a399f157e0481d4de1ae6e0ef37b6f104b8e664d7c9344a37195fe70e930bfe37043360eff83afec3f18231f5017f9b67f7879088acd214f
|
7
|
+
data.tar.gz: 576a9b67c836258bde3b18de79333f4d0adc22d0deb123100af5cf77b663a17613faf818fcf59218bb4d45b5c5e99197dcb9bd54da758b0caf0e25c37d361516
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2019 Ajit Singh
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
# data_verifier
|
2
|
+
|
3
|
+
There are times when we change the approach of modifying data and want to verify
|
4
|
+
that the data modified by the new approach is same as the old approach.
|
5
|
+
This gem is build for such verifications.
|
6
|
+
|
7
|
+
## Motivation
|
8
|
+
|
9
|
+
In my project, we replicate the data from other systems. There was a requirement where we changed the source of the data
|
10
|
+
and code to replicate the data to our system. In testing phase we wanted to create a validation sheet,
|
11
|
+
which can show the difference b/w the data in our system before and after the new source.
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
```ruby
|
16
|
+
gem 'data_verifier'
|
17
|
+
```
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
This gem has to be used in two phases:
|
21
|
+
|
22
|
+
1. Build Phase: Use this phase to build the baseline of the data before changing the code/approach
|
23
|
+
2. Verification Phase: Use this phase to verify the new data against the baseline data
|
24
|
+
|
25
|
+
#### Config:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'data_verifier'
|
29
|
+
|
30
|
+
QUERIES = {
|
31
|
+
users_table: "select * from users where id=100",
|
32
|
+
phones_table: "select * from phones where user_id=100",
|
33
|
+
addresses_table: "select * from addresses where user_id=100",
|
34
|
+
}
|
35
|
+
|
36
|
+
config = DataVerifier::Config.new do |c|
|
37
|
+
c.db_adapter = :oracle
|
38
|
+
c.db_user = 'my_db_user'
|
39
|
+
c.db_password = 'my_pass'
|
40
|
+
c.db_host = 'localhost'
|
41
|
+
c.db_name = 'test_db'
|
42
|
+
c.db_port = '1521'
|
43
|
+
c.data_identifier = 'user_id_100'
|
44
|
+
c.queries = QUERIES
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
#### Building Baseline Data:
|
49
|
+
|
50
|
+
The below code will execute all the queries and store their result in json files.
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
DataVerifier::BaselineBuilder.new(config).build
|
54
|
+
```
|
55
|
+
|
56
|
+
#### Verification:
|
57
|
+
|
58
|
+
Below code will again execute the queries and will compare it with the baseline data.
|
59
|
+
After comparision it will create an excel file of the result.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
DataVerifier::Validator.new(config).generate_validation_file
|
63
|
+
```
|
64
|
+
|
65
|
+
#### Result:
|
66
|
+
|
67
|
+
<img src="https://github.com/ajitsing/ScreenShots/blob/master/data_verifier/data_verifier_result.png"/>
|
68
|
+
|
69
|
+
## License
|
70
|
+
```license
|
71
|
+
MIT License
|
72
|
+
|
73
|
+
Copyright (c) 2019 Ajit Singh
|
74
|
+
|
75
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
76
|
+
of this software and associated documentation files (the "Software"), to deal
|
77
|
+
in the Software without restriction, including without limitation the rights
|
78
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
79
|
+
copies of the Software, and to permit persons to whom the Software is
|
80
|
+
furnished to do so, subject to the following conditions:
|
81
|
+
|
82
|
+
The above copyright notice and this permission notice shall be included in all
|
83
|
+
copies or substantial portions of the Software.
|
84
|
+
|
85
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
86
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
87
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
88
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
89
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
90
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
91
|
+
SOFTWARE.
|
92
|
+
```
|
@@ -3,32 +3,44 @@ require 'sequel'
|
|
3
3
|
|
4
4
|
module DataVerifier
|
5
5
|
class BaselineBuilder
|
6
|
-
def initialize
|
7
|
-
@
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
database: @config.db_name,
|
14
|
-
max_connections: @config.db_max_connections)
|
6
|
+
def initialize
|
7
|
+
@configs = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def with(config)
|
11
|
+
@configs << config
|
12
|
+
self
|
15
13
|
end
|
16
14
|
|
17
15
|
def build
|
18
|
-
@
|
19
|
-
|
20
|
-
|
16
|
+
@configs.each do |config|
|
17
|
+
db = create_db_connection(config)
|
18
|
+
|
19
|
+
config.queries.each do |tag, query|
|
20
|
+
puts "Executing => #{query}\n"
|
21
|
+
data = db.fetch(query)
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
File.open(data_file_name(config, tag), 'w') do |file|
|
24
|
+
file.write JSON.dump(data.all)
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
27
29
|
|
28
30
|
private
|
29
|
-
def data_file_name(tag)
|
30
|
-
identifier =
|
31
|
+
def data_file_name(config, tag)
|
32
|
+
identifier = config.data_identifier.nil? ? '' : "#{config.data_identifier}_"
|
31
33
|
"#{identifier}#{tag}.json"
|
32
34
|
end
|
35
|
+
|
36
|
+
def create_db_connection(config)
|
37
|
+
Sequel.connect(adapter: config.db_adapter,
|
38
|
+
user: config.db_user,
|
39
|
+
password: config.db_password,
|
40
|
+
host: config.db_host,
|
41
|
+
port: config.db_port,
|
42
|
+
database: config.db_name,
|
43
|
+
max_connections: config.db_max_connections)
|
44
|
+
end
|
33
45
|
end
|
34
46
|
end
|
@@ -4,71 +4,99 @@ require 'axlsx'
|
|
4
4
|
|
5
5
|
module DataVerifier
|
6
6
|
class Validator
|
7
|
-
def initialize(
|
8
|
-
@
|
9
|
-
@
|
10
|
-
user: @config.db_user,
|
11
|
-
password: @config.db_password,
|
12
|
-
host: @config.db_host,
|
13
|
-
port: @config.db_port,
|
14
|
-
database: @config.db_name,
|
15
|
-
max_connections: @config.db_max_connections)
|
7
|
+
def initialize(report_name = 'data_verifier')
|
8
|
+
@report_name = report_name
|
9
|
+
@excel = Axlsx::Package.new
|
16
10
|
end
|
17
11
|
|
18
|
-
def
|
19
|
-
|
12
|
+
def validate_using(config)
|
13
|
+
db = create_db_connection(config)
|
20
14
|
|
21
|
-
|
15
|
+
config.queries.each do |tag, query|
|
22
16
|
puts "Executing => #{query}\n"
|
23
|
-
|
24
|
-
|
17
|
+
|
18
|
+
new_data = db.fetch(query)
|
19
|
+
old_data = JSON.parse(File.read(data_file_name(config, tag)))
|
20
|
+
|
21
|
+
update_excel(tag, new_data, old_data)
|
25
22
|
end
|
26
23
|
|
27
|
-
|
24
|
+
self
|
28
25
|
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
"#{identifier}#{tag}.json"
|
27
|
+
def generate_report
|
28
|
+
@excel.serialize("#{@report_name}.xlsx")
|
33
29
|
end
|
34
30
|
|
35
|
-
|
36
|
-
|
31
|
+
private
|
32
|
+
def create_db_connection(config)
|
33
|
+
Sequel.connect(adapter: config.db_adapter,
|
34
|
+
user: config.db_user,
|
35
|
+
password: config.db_password,
|
36
|
+
host: config.db_host,
|
37
|
+
port: config.db_port,
|
38
|
+
database: config.db_name,
|
39
|
+
max_connections: config.db_max_connections)
|
37
40
|
end
|
38
41
|
|
39
|
-
def update_excel(
|
40
|
-
|
41
|
-
|
42
|
-
excel.workbook.add_worksheet(name: sheet_name.to_s) do |s|
|
43
|
-
red_color = Axlsx::Color.new
|
44
|
-
red_color.rgb = 'C40101'
|
42
|
+
def update_excel(sheet_name, new_data, old_data)
|
43
|
+
header_color = "43B275"
|
44
|
+
header = %w(Field Before After)
|
45
45
|
|
46
|
-
|
47
|
-
|
46
|
+
header_style_opts = {bg_color: header_color, b: true, sz: 16, alignment: {horizontal: :center}, color: white_color}
|
47
|
+
data_style_opts = {sz: 13, alignment: {horizontal: :left}}
|
48
|
+
error_style_opts = {sz: 12, alignment: {horizontal: :left}, color: red_color, b: true}
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
@excel.workbook.add_worksheet(name: sheet_name.to_s) do |s|
|
51
|
+
header_style = s.styles.add_style header_style_opts
|
52
|
+
data_style = s.styles.add_style data_style_opts
|
53
|
+
error_data_style = s.styles.add_style error_style_opts
|
52
54
|
|
53
|
-
s.add_row
|
55
|
+
s.add_row header, style: header_style
|
54
56
|
s.row_style(0, header_style)
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
+
new_data.each_with_index do |db_row, index|
|
59
|
+
baseline_row = old_data[index]
|
58
60
|
|
59
|
-
db_row.each do |
|
60
|
-
|
61
|
-
|
61
|
+
db_row.each do |db_field, new_value|
|
62
|
+
field = db_field.to_s.upcase
|
63
|
+
old_value = baseline_row.nil? ? "" : baseline_row[db_field.to_s].to_s
|
64
|
+
cell_style = old_value == new_value.to_s ? data_style : error_data_style
|
62
65
|
|
63
|
-
|
64
|
-
s.add_row data, style: [conditional_formatting, data_style, data_style]
|
66
|
+
s.add_row [field, old_value, new_value.to_s], style: [cell_style, cell_style, cell_style]
|
65
67
|
end
|
66
68
|
|
67
|
-
s.add_row
|
68
|
-
s.add_row
|
69
|
-
s.add_row
|
69
|
+
s.add_row empty_row
|
70
|
+
s.add_row empty_row, style: [header_style, header_style, header_style]
|
71
|
+
s.add_row empty_row
|
70
72
|
end
|
71
73
|
end
|
72
74
|
end
|
75
|
+
|
76
|
+
def data_file_name(config, tag)
|
77
|
+
"#{identifier(config)}#{tag}.json"
|
78
|
+
end
|
79
|
+
|
80
|
+
def identifier(config)
|
81
|
+
config.data_identifier.nil? ? '' : "#{config.data_identifier}_"
|
82
|
+
end
|
83
|
+
|
84
|
+
def empty_row
|
85
|
+
["", "", ""]
|
86
|
+
end
|
87
|
+
|
88
|
+
def red_color
|
89
|
+
red_color = Axlsx::Color.new
|
90
|
+
red_color.rgb = 'C40101'
|
91
|
+
|
92
|
+
red_color
|
93
|
+
end
|
94
|
+
|
95
|
+
def white_color
|
96
|
+
white_color = Axlsx::Color.new
|
97
|
+
white_color.rgb = 'FFFFFF'
|
98
|
+
|
99
|
+
white_color
|
100
|
+
end
|
73
101
|
end
|
74
102
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'data_verifier'
|
2
|
+
|
3
|
+
describe DataVerifier::BaselineBuilder do
|
4
|
+
describe '#build' do
|
5
|
+
let(:db) {double(:db)}
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
expect(Sequel).to receive(:connect).and_return(db)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should execute queries and store result in json files' do
|
12
|
+
queries = {
|
13
|
+
users_table: 'select * from users where id=100',
|
14
|
+
addresses_table: 'select * from addresses where user_id=100'
|
15
|
+
}
|
16
|
+
|
17
|
+
config = DataVerifier::Config.new do |c|
|
18
|
+
c.data_identifier = '100'
|
19
|
+
c.queries = queries
|
20
|
+
end
|
21
|
+
|
22
|
+
builder = DataVerifier::BaselineBuilder.new
|
23
|
+
|
24
|
+
expect(db).to receive(:fetch).with(queries[:users_table]).and_return(double(:users))
|
25
|
+
expect(db).to receive(:fetch).with(queries[:addresses_table]).and_return(double(:addresses))
|
26
|
+
|
27
|
+
expect(File).to receive(:open).with('100_users_table.json', 'w')
|
28
|
+
expect(File).to receive(:open).with('100_addresses_table.json', 'w')
|
29
|
+
|
30
|
+
builder.with(config).build
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should not add prefix to json files when identifier is not given' do
|
34
|
+
queries = {
|
35
|
+
users_table: 'select * from users where id=100'
|
36
|
+
}
|
37
|
+
|
38
|
+
config = DataVerifier::Config.new do |c|
|
39
|
+
c.queries = queries
|
40
|
+
end
|
41
|
+
|
42
|
+
builder = DataVerifier::BaselineBuilder.new
|
43
|
+
|
44
|
+
expect(db).to receive(:fetch).with(queries[:users_table]).and_return(double(:users))
|
45
|
+
expect(File).to receive(:open).with('users_table.json', 'w')
|
46
|
+
|
47
|
+
builder.with(config).build
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'data_verifier'
|
2
|
+
|
3
|
+
describe DataVerifier::Validator do
|
4
|
+
describe '#generate_validation_file' do
|
5
|
+
let(:db) {double(:db)}
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
expect(Sequel).to receive(:connect).and_return(db)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should create result excel file' do
|
12
|
+
queries = {
|
13
|
+
users_table: 'select * from users where id=100',
|
14
|
+
addresses_table: 'select * from addresses where user_id=100'
|
15
|
+
}
|
16
|
+
|
17
|
+
config = DataVerifier::Config.new do |c|
|
18
|
+
c.data_identifier = '100'
|
19
|
+
c.queries = queries
|
20
|
+
end
|
21
|
+
|
22
|
+
excel = double(:excel)
|
23
|
+
expect(Axlsx::Package).to receive(:new).and_return(excel)
|
24
|
+
|
25
|
+
validator = DataVerifier::Validator.new('test_result')
|
26
|
+
|
27
|
+
expect(db).to receive(:fetch).with(queries[:users_table]).and_return(double(:users))
|
28
|
+
expect(db).to receive(:fetch).with(queries[:addresses_table]).and_return(double(:addresses))
|
29
|
+
|
30
|
+
expect(File).to receive(:read).with('100_users_table.json').and_return("{}")
|
31
|
+
expect(File).to receive(:read).with('100_addresses_table.json').and_return("{}")
|
32
|
+
|
33
|
+
work_book = double(:workbook)
|
34
|
+
expect(excel).to receive(:workbook).and_return(work_book).twice
|
35
|
+
|
36
|
+
expect(work_book).to receive(:add_worksheet).with(name: 'users_table')
|
37
|
+
expect(work_book).to receive(:add_worksheet).with(name: 'addresses_table')
|
38
|
+
|
39
|
+
expect(excel).to receive(:serialize).with('test_result.xlsx')
|
40
|
+
|
41
|
+
validator.validate_using(config).generate_report
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data_verifier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ajit Singh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: axlsx
|
@@ -75,12 +75,16 @@ files:
|
|
75
75
|
- ".gitignore"
|
76
76
|
- Gemfile
|
77
77
|
- Gemfile.lock
|
78
|
+
- LICENSE
|
79
|
+
- README.md
|
78
80
|
- data_verifier.gemspec
|
79
81
|
- lib/data_verifier.rb
|
80
82
|
- lib/data_verifier/baseline_builder.rb
|
81
83
|
- lib/data_verifier/config.rb
|
82
84
|
- lib/data_verifier/validator.rb
|
83
85
|
- lib/data_verifier/version.rb
|
86
|
+
- spec/lib/data_verifier/baseline_builder_spec.rb
|
87
|
+
- spec/lib/data_verifier/validator_spec.rb
|
84
88
|
homepage: https://github.com/ajitsing/data_verifier
|
85
89
|
licenses:
|
86
90
|
- MIT
|
@@ -105,4 +109,6 @@ rubygems_version: 2.7.6
|
|
105
109
|
signing_key:
|
106
110
|
specification_version: 4
|
107
111
|
summary: Verify data after performing series of operations
|
108
|
-
test_files:
|
112
|
+
test_files:
|
113
|
+
- spec/lib/data_verifier/baseline_builder_spec.rb
|
114
|
+
- spec/lib/data_verifier/validator_spec.rb
|