lx_data_validation 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5d57c15e760b4b13cd67d124d6e0c66c1f5d603c
4
+ data.tar.gz: 05207e5b3e1d45257a60e02cf4da04bf8b88eab0
5
+ SHA512:
6
+ metadata.gz: 7183dc0078c905252f2a9179ff5a05637fbeb863e3de117c672f74bec84ce522574a55d30b7b32588dcb9f604ccc276df709ca53ffb6752d1af09bc8211a4901
7
+ data.tar.gz: 4473bce485ba3e274b347ead5e9a0e0f1c47f6f3e73c6058649ca400b07fe5f8470ac6cf523199519de291bf8e1b3debff8b41001dd5268fc2dd56a62823d821
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.0.0
5
+ before_install: gem install bundler -v 1.12.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in data_validation.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Roger Tong
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # DataValidation
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/data_validation`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'data_validation'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install lx_data_validation
21
+
22
+ ## Usage
23
+
24
+
25
+ ## Development
26
+
27
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
28
+
29
+ ## Contributing
30
+
31
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/data_validation.
32
+
33
+
34
+ ## License
35
+
36
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
37
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/compare ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'data_validation'
4
+
5
+ DataValidation.compare_with_season ARGV[0]
data/config/hosts.yml ADDED
@@ -0,0 +1,8 @@
1
+ int:
2
+ web_request_host: http://int-laxpower-phpadmin-01w.dev.activenetwork.com
3
+ api_request_host: https://awmobile-vip.qa.aw.dev.activenetwork.com
4
+
5
+ prod:
6
+ web_request_host: http://php.admin.laxpower.com
7
+ api_request_host: https://awmobile.active.com
8
+
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'data_validation/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "lx_data_validation"
8
+ spec.version = DataValidation::VERSION
9
+ spec.authors = ["Roger Tong"]
10
+ spec.email = ["Roger.Tong@activenetwork.com", "tomtongt@live.com"]
11
+
12
+ spec.summary = "Data validation for LaxPower"
13
+ spec.description = "The validation is to compare values between web page values and mobile api responses"
14
+ spec.homepage = "https://gitlab.dev.activenetwork.com/rtong/data-validation-for-laxpower"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RupwdbyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata['allowed_push_host'] = "input later"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
23
+ # end
24
+
25
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
26
+ spec.bindir = "bin"
27
+ spec.executables = ["compare"]
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.required_ruby_version = '>= 2.1.4'
31
+
32
+ spec.add_development_dependency "bundler", "~> 1.12"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.0"
35
+
36
+ spec.add_runtime_dependency 'nokogiri', '1.6.6.2'
37
+ spec.add_runtime_dependency 'httparty', '0.8.1'
38
+
39
+ end
@@ -0,0 +1,169 @@
1
+ require 'data_validation/data_access'
2
+ require 'logger'
3
+
4
+ module DataValidation
5
+ module Comparison
6
+ class ComparisonBase
7
+ attr_reader :web_url, :logger_name, :category, :season, :division_id
8
+
9
+ def initialize(web_url)
10
+ @web_url = web_url
11
+ end
12
+
13
+ def compare
14
+ if api_path.nil?
15
+ raise 'Please define api_path'
16
+ end
17
+
18
+ if field_array.nil?
19
+ raise 'Please define field_array'
20
+ end
21
+
22
+ data_access = DataValidation::DataAccess.new(web_url, DataValidation.api_request_host + api_path, determine_request_body_and_logger_name)
23
+
24
+ puts 'requesting web page...'
25
+ web_data = data_access.get_main_table_data
26
+ puts 'requesting mobile api data: ' + DataValidation.api_request_host + api_path
27
+ api_data = data_access.get_response_from_mobile_api
28
+
29
+ if web_data.length != api_data['results']['results']['total']
30
+ logger.error "The record size between web page and api data is not the same: #{web_data.length} -- #{api_data['results']['results']['total']}"
31
+ return
32
+ end
33
+
34
+ web_data.each_with_index do |item, index|
35
+ team = api_data['results']['results']['teams'][index]
36
+
37
+ i = 0
38
+ field_array.each do |filed_name|
39
+
40
+ if filed_name.is_a? String
41
+ team_value = team[filed_name]
42
+ elsif filed_name.is_a? Array
43
+ team_value = team[filed_name[0]][filed_name[1]]
44
+ else
45
+ i += 1
46
+ next
47
+ end
48
+
49
+ if item.length < field_array.length && empty_field && empty_field == filed_name ## when the field is empty in the table
50
+ logger.error "team #{item[0]}'s #{filed_name} is not empty: #{team_value}" unless (team_value == 0 || team_value.nil?)
51
+ next
52
+ end
53
+
54
+
55
+ unless (team_value.is_a?(String) && team_value.include?(item[i])) ||
56
+ (team_value.is_a?(Float) && team_value == item[i].to_f) ||
57
+ (team_value.is_a?(Integer) && team_value == item[i].to_i)
58
+
59
+ logger.error "team #{item[0]}'s #{filed_name} is not correct: #{item[i]} -- #{team_value}"
60
+ end
61
+
62
+ i += 1
63
+ end
64
+
65
+ end
66
+ end
67
+
68
+ def compare_conf_standings(api_data, data_access)
69
+ puts 'Start to compare conf ranking tables'
70
+ conf_standing_data = data_access.conf_standing_data
71
+ conf_standing_data.each do |standing|
72
+ full_conf = ''
73
+ # puts standing.to_s
74
+ standing.each_with_index do |record, i|
75
+ if i == 0
76
+ state = record[0]
77
+ team_class = record[1]
78
+ conf = record[2]
79
+ full_conf = "#{state}, #{team_class}, #{conf}"
80
+
81
+ api_data = data_access.get_response_from_mobile_api_with_params(conf_rank_api_url, %Q|{"season": "#{season}", "conference": {"category": "#{category}", "conference": "#{conf}", "divisionId": #{division_id.to_i}, "state": "#{state}", "teamClass": "#{team_class}"}, "currPage": 1, "pageSize": 1000}|)
82
+
83
+ if api_data['results']['results']['total'] != standing.length - 1
84
+ logger.error "standing for #{full_conf} has incorrect length: #{standing.length - 1} : #{api_data['results']['results']['total']}"
85
+ break
86
+ end
87
+ else
88
+
89
+ team_data = api_data['results']['results']['teams'][i - 1]
90
+
91
+ record.each_with_index do |item, index|
92
+ if index == 0 && item.to_i != team_data['rank']
93
+ elsif index == 1 && item.to_f != team_data['powerRating']
94
+ logger.error "team #{i} has incorrect powerRating in #{full_conf}: #{item.to_f} -- #{team_data['powerRating']}"
95
+ elsif index == 2 && item.to_i != team_data['conference']['wins']
96
+ logger.error "team #{i} has incorrect conference wins in #{full_conf}: #{item.to_i} -- #{team_data['conference']['wins']}"
97
+ elsif index == 3 && item.to_i != team_data['conference']['losses']
98
+ logger.error "team #{i} has incorrect conference losses in #{full_conf}: #{item.to_i} -- #{team_data['conference']['losses']}"
99
+ elsif index == 4 && item.to_i != team_data['conference']['ties']
100
+ logger.error "team #{i} has incorrect conference ties in #{full_conf}: #{item.to_i} -- #{team_data['conference']['ties']}"
101
+ elsif index == 5 && item.to_f != team_data['winLossConf']
102
+ logger.error "team #{i} has incorrect winLossConf in #{full_conf}: #{item.to_f} -- #{team_data['winLossConf']}"
103
+ elsif index == 6 && item.to_i != team_data['total']['wins']
104
+ logger.error "team #{i} has incorrect total wins in #{full_conf}: #{item.to_i} -- #{team_data['total']['wins']}"
105
+ elsif index == 7 && item.to_i != team_data['total']['losses']
106
+ logger.error "team #{i} has incorrect total losses in #{full_conf}: #{item.to_i} -- #{team_data['total']['losses']}"
107
+ elsif index == 8 && item.to_i != team_data['total']['ties']
108
+ logger.error "team #{i} has incorrect total ties in #{full_conf}: #{item.to_i} -- #{team_data['total']['ties']}"
109
+ elsif index == 9 && item.to_f != team_data['winLossTotal']
110
+ logger.error "team #{i} has incorrect winLossTotal in #{full_conf}: #{item.to_f} -- #{team_data['winLossTotal']}"
111
+ end
112
+ end
113
+ end
114
+
115
+ end
116
+ end
117
+ end
118
+
119
+ protected
120
+
121
+ def api_path
122
+
123
+ end
124
+
125
+ def field_array
126
+
127
+ end
128
+
129
+ def empty_field
130
+
131
+ end
132
+
133
+ private
134
+
135
+ def logger
136
+ @logger ||= begin
137
+ tokens = logger_name.split('/')
138
+ 1.upto(tokens.size - 1) do |n|
139
+ dir = tokens[0...n].join('/')
140
+ Dir.mkdir(dir) unless Dir.exist?(dir)
141
+ end
142
+ Logger.new File.new(logger_name, 'w')
143
+ end
144
+ end
145
+
146
+ def determine_request_body_and_logger_name
147
+ @category = if web_url.match /bingrl/
148
+ 'GIRLS'
149
+ elsif web_url.match /binboy/
150
+ 'BOYS'
151
+ elsif web_url.match /binmen/
152
+ 'MEN'
153
+ elsif web_url.match /binwom/
154
+ 'WOMEN'
155
+ end
156
+
157
+ @season = "20#{web_url.match(/update(..)/)[1]}"
158
+
159
+ @division_id = web_url.match(/(\d+)\.php/)[1].to_i
160
+
161
+ operation = web_url.match(/\/([a-z]+)\d+.php/)[1]
162
+
163
+ @logger_name = "log/#{season}/#{category.downcase}/#{operation}/#{operation}_#{season}_#{category}_#{division_id}.log"
164
+
165
+ %Q|{"category":"#{category}","season":#{season},"divisionId":#{division_id},"currPage":1,"pageSize":1000}|
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,37 @@
1
+ require 'data_validation/comparison/div_ranking_pr_comparison'
2
+ require 'data_validation/comparison/ranking_table_mw_sos_comparison'
3
+ require 'data_validation/comparison/ranking_table_mw_rpi_comparison'
4
+ require 'data_validation/comparison/div_ranking_wl_comparison'
5
+ require 'data_validation/comparison/ranking_table_mw_qw_comparison'
6
+ require 'data_validation/comparison/ranking_table_mw_poll_comparison'
7
+ require 'data_validation/comparison/ranking_table_mw_trend_comparison'
8
+ require 'data_validation/comparison/ranking_table_mw_tsi_comparison'
9
+ require 'data_validation/comparison/ranking_table_mw_pr_comparison'
10
+
11
+ module DataValidation
12
+ module Comparison
13
+ class ComparisonFactory
14
+ def self.get_comparison(url)
15
+ if url.match /update\d\d\/bin(boy|grl)\/rating\d+.php/ # division Computer Rating page for boys/girls
16
+ return DivRankingPrComparison.new url
17
+ elsif url.match /update\d\d\/bin\S+\/rating\d+.php/ # division Computer Rating page for men and women
18
+ return RankingTableMwPrComparison.new url
19
+ elsif url.match /update\d\d\/bin\S+\/sos\d+.php/ # division Strength of Schedule page for boys/girls
20
+ return RankingTableMwSosComparison.new url
21
+ elsif url.match /update\d\d\/bin\S+\/rpi\d+.php/ # division RPI Rankings page for boys/girls
22
+ return RankingTableMwRpiComparison.new url
23
+ elsif url.match /update\d\d\/bin\S+\/wl\d+.php/ # division win-loss factor page for boys/girls
24
+ return DivRankingWlComparison.new url
25
+ elsif url.match /update\d\d\/bin\S+\/qwf\d+.php/ # division Quality Win Factor page for boys/girls
26
+ return RankingTableMwQwComparison.new url
27
+ elsif url.match /update\d\d\/bin\S+\/poll\d+.php/ # Poll page for collage division
28
+ return RankingTableMwPollComparison.new url
29
+ elsif url.match /update\d\d\/bin\S+\/trend\d+.php/ # Trend page for collage division
30
+ return RankingTableMwTrendComparison.new url
31
+ elsif url.match /update\d\d\/bin\S+\/tsi\d+.php/ # Trend page for collage division
32
+ return RankingTableMwTsiComparison.new url
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,72 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwPollComparison < ComparisonBase
6
+
7
+ def compare
8
+
9
+ if api_path.nil?
10
+ raise 'Please define api_path'
11
+ end
12
+
13
+ data_access = DataValidation::DataAccess.new(web_url, DataValidation.api_request_host + api_path, determine_request_body_and_logger_name)
14
+
15
+ puts 'requesting web page...'
16
+ web_data = data_access.get_main_table_data
17
+ puts 'requesting mobile api data: ' + DataValidation.api_request_host + api_path
18
+ api_data = data_access.get_response_from_mobile_api
19
+
20
+ if web_data.length != api_data['results']['results']['total']
21
+ logger.error "The record size between web page and api data is not the same: #{web_data.length} -- #{api_data['results']['results']['total']}"
22
+ return
23
+ end
24
+
25
+ web_data.each_with_index do |item, index|
26
+ team = api_data['results']['results']['teams'][index]
27
+
28
+ field_array.each_with_index do |filed_name, index|
29
+ if filed_name.is_a? String
30
+ team_value = team[filed_name]
31
+ elsif filed_name.is_a? Array
32
+ team_value = team[filed_name[0]][filed_name[1]]
33
+ else
34
+ next
35
+ end
36
+
37
+ unless (team_value.is_a?(String) && team_value.include?(item[index])) ||
38
+ (team_value.is_a?(Float) && team_value == item[index].to_f) ||
39
+ (team_value.is_a?(Integer) && team_value == item[index].to_i)
40
+
41
+ logger.error "team #{item[0]}'s #{filed_name} is not correct: #{item[index]} -- #{team_value}"
42
+ end
43
+ end
44
+
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+
51
+ def determine_request_body_and_logger_name
52
+ category = if web_url.match /bingrl/
53
+ 'GIRLS'
54
+ elsif web_url.match /binboy/
55
+ 'BOYS'
56
+ elsif web_url.match /binmen/
57
+ 'MEN'
58
+ elsif web_url.match /binwom/
59
+ 'WOMEN'
60
+ end
61
+
62
+ season = "20#{web_url.match(/update(..)/)[1]}"
63
+
64
+ division_id = web_url.match(/(\d+)\.php/)[1].to_i
65
+
66
+ operation = web_url.match(/\/([a-z]+)\d+.php/)[1]
67
+
68
+ @logger_name = "log/#{season}/#{category.downcase}/#{operation}/#{operation}_#{season}_#{category}_#{division_id}.log"
69
+
70
+ %Q|{"season":"#{season}", "conference": {"category": "#{category}",} "divisionId":#{division_id},"currPage":1,"pageSize":1000}|
71
+ end
72
+ end
@@ -0,0 +1,78 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class DivRankingPrComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/divisionRankingPr'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', 'powerRating', 'regInPr', 'correction', 'championship', 'winLossTotal', %w|record wins|, %w|record losses|, %w|record ties|]
13
+ end
14
+
15
+ def empty_field
16
+ ''
17
+ end
18
+
19
+ def compare
20
+
21
+ data_access = DataValidation::DataAccess.new(web_url, DataValidation.api_request_host + api_path, determine_request_body_and_logger_name)
22
+
23
+ puts 'requesting web page...'
24
+ web_data = data_access.get_main_table_data
25
+ puts 'requesting mobile api data: ' + DataValidation.api_request_host + api_path
26
+ api_data = data_access.get_response_from_mobile_api
27
+
28
+ if web_data.length != api_data['results']['results']['total']
29
+ logger.error "The record size between web page and api data is not the same: #{web_data.length} -- #{api_data['results']['results']['total']}"
30
+ return
31
+ end
32
+
33
+ ## compare first table
34
+ web_data.each_with_index do |item, index|
35
+ team = api_data['results']['results']['teams'][index]
36
+
37
+ i = 0
38
+ field_array.each do |filed_name|
39
+
40
+ if filed_name.is_a? String
41
+ team_value = team[filed_name]
42
+ elsif filed_name.is_a? Array
43
+ team_value = team[filed_name[0]][filed_name[1]]
44
+ else
45
+ next
46
+ end
47
+
48
+ if item.length < field_array.length && empty_field && empty_field == filed_name ## when the field is possibly empty in the table
49
+ logger.error "team #{item[0]}'s #{filed_name} is not empty: #{team_value}" unless (team_value == 0 || team_value.nil?)
50
+ next
51
+ end
52
+
53
+
54
+ unless (team_value.is_a?(String) && team_value.include?(item[i])) ||
55
+ (team_value.is_a?(Float) && team_value == item[i].to_f) ||
56
+ (team_value.is_a?(Integer) && team_value == item[i].to_i)
57
+
58
+ logger.error "team #{item[0]}'s #{filed_name} is not correct: #{item[i]} -- #{team_value}"
59
+ end
60
+
61
+ i += 1
62
+ end
63
+
64
+ end
65
+
66
+ ## compare standing tables
67
+ compare_conf_standings(api_data, data_access)
68
+ end
69
+
70
+
71
+
72
+ def conf_rank_api_url
73
+ DataValidation.api_request_host + '/rest/LaxPower/conferenceRankingTable'
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,17 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class DivRankingWlComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/divisionRankingWl'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', 'rank', 'winLossTotal', 'rankDivision', 'winLossDivision', 'rankDate', 'winLossDate', 'rankRoad', 'winLossRoad', %w|record wins|, %w|record losses|, %w|record ties|]
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwPollComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWpoll'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', %w|record wins|, %w|record losses|, %w|record ties|, 'pollPoint', 'pollFirst', 'lastWeek']
13
+ end
14
+
15
+ def empty_field
16
+ 'pollFirst'
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwPrComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWpr'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', 'powerRating', 'pollRank', 'sosRank', 'rpiRank', 'qwfRank', 'tsiRank', %w|record wins|, %w|record losses|, %w|record ties|]
13
+ end
14
+
15
+ def empty_field
16
+ 'pollRank'
17
+ end
18
+
19
+ def compare
20
+ data_access = DataValidation::DataAccess.new(web_url, DataValidation.api_request_host + api_path, determine_request_body_and_logger_name)
21
+
22
+ puts 'requesting web page...'
23
+ web_data = data_access.get_main_table_data
24
+ puts 'requesting mobile api data: ' + DataValidation.api_request_host + api_path
25
+ api_data = data_access.get_response_from_mobile_api
26
+
27
+ if web_data.length != api_data['results']['results']['total']
28
+ logger.error "The record size between web page and api data is not the same: #{web_data.length} -- #{api_data['results']['results']['total']}"
29
+ return
30
+ end
31
+
32
+ ## compare first table
33
+ web_data.each_with_index do |item, index|
34
+ team = api_data['results']['results']['teams'][index]
35
+
36
+ i = 0
37
+ field_array.each do |filed_name|
38
+
39
+ if filed_name.is_a? String
40
+ team_value = team[filed_name]
41
+ elsif filed_name.is_a? Array
42
+ team_value = team[filed_name[0]][filed_name[1]]
43
+ else
44
+ next
45
+ end
46
+
47
+ if item.length < field_array.length && empty_field && empty_field == filed_name ## when the field is possibly empty in the table
48
+ logger.error "team #{item[0]}'s #{filed_name} is not empty: #{team_value}" unless (team_value == 0 || team_value.nil?)
49
+ next
50
+ end
51
+
52
+
53
+ unless (team_value.is_a?(String) && team_value.include?(item[i])) ||
54
+ (team_value.is_a?(Float) && team_value == item[i].to_f) ||
55
+ (team_value.is_a?(Integer) && team_value == item[i].to_i)
56
+
57
+ logger.error "team #{item[0]}'s #{filed_name} is not correct: #{item[i]} -- #{team_value}"
58
+ end
59
+
60
+ i += 1
61
+ end
62
+
63
+ end
64
+
65
+ compare_conf_standings api_data, data_access
66
+ end
67
+
68
+ def conf_rank_api_url
69
+ DataValidation.api_request_host + '/rest/LaxPower/conferenceRankingTable'
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,17 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwQwComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWqw'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', 'qwPrRank', 'qualityWinsPr', nil, 'qualityWinsPoll', 'qwRpiRank', 'qualityWinsRpi', %w|record wins|, %w|record losses|, %w|record ties|]
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwRpiComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWrpi'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', nil, 'rpi', 'signWinsRank', 'signficantWins', 'signLossRank', 'signficantLosses',
13
+ %w|recordTotal wins|, %w|recordTotal losses|, %w|recordTotal ties|,
14
+ %w|recordRoad wins|, %w|recordRoad losses|, %w|recordRoad ties|,
15
+ %w|recordNeutral wins|, %w|recordNeutral losses|, %w|recordNeutral ties|,
16
+ %w|recordHome wins|, %w|recordHome losses|, %w|recordHome ties|]
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwSosComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWsos'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', 'totalGames', nil, 'sosAverage', 'sosWeightedRank', 'sosWeighted', 'sosRpiRank', 'sosRpi', %w|record wins|, %w|record losses|, %w|record ties|]
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwTrendComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWtrend
9
+ '
10
+ end
11
+
12
+ def field_array
13
+ ['rank', 'teamName', %w|record wins|, %w|record losses|, %w|record ties|, 'trend']
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'data_validation/comparison/comparison_base'
2
+
3
+ module DataValidation
4
+ module Comparison
5
+ class RankingTableMwTsiComparison < ComparisonBase
6
+
7
+ def api_path
8
+ '/rest/LaxPower/rankingTableMWtsi'
9
+ end
10
+
11
+ def field_array
12
+ ['rank', 'teamName', 'tsi', 'pollRank', 'prRank', 'rpiRank', 'sosRank', 'qwf', 'loss', 'trend', %w|record wins|, %w|record losses|, %w|record ties|]
13
+ end
14
+
15
+ def empty_field
16
+ 'pollRank'
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,140 @@
1
+ require 'nokogiri'
2
+ require 'httparty'
3
+ require 'open-uri'
4
+
5
+ module DataValidation
6
+ class DataAccess
7
+
8
+ attr_reader :html_url, :api_url, :api_body, :conf_standing_data
9
+
10
+ def initialize(html_url, api_url, api_body)
11
+ @html_url = html_url
12
+ @api_url = api_url
13
+ @api_body = api_body
14
+ end
15
+
16
+ def get_main_table_data
17
+ doc = Nokogiri::HTML(open(html_url))
18
+
19
+ if html_url.match /rating/
20
+ extract_conf_standing_data(doc)
21
+ end
22
+
23
+ team_names = doc.search('div.cs1 div.cs1 a').map { |node| node.text if /^[A-Z\d]+.PHP$/.match(node.attr('href')) }.compact ## extract team names
24
+
25
+ doc.search('div.cs1 div.cs1 a').remove ## then remove all links from the doc
26
+
27
+ index = 0
28
+ doc.search('div.cs1 div.cs1').text.lines.map do |line|
29
+ if /^\s*(?<rank>\d+)\s+(?<rest>.*)/ =~ line
30
+ data_array = ([rank] << team_names[index]) + rest.split(' ')
31
+ index += 1
32
+ data_array
33
+ end
34
+ end.compact
35
+ end
36
+
37
+ def extract_conf_standing_data(doc)
38
+ category = if html_url.match /bingrl/
39
+ 'GIRLS'
40
+ elsif html_url.match /binboy/
41
+ 'BOYS'
42
+ elsif html_url.match /binmen/
43
+ 'MEN'
44
+ elsif html_url.match /binwom/
45
+ 'WOMEN'
46
+ end
47
+
48
+ season = "20#{html_url.match(/update(..)/)[1]}"
49
+
50
+ div_id = html_url.match(/(\d+)\.php/)[1].to_i
51
+
52
+ conf_data = get_conference(season, category, div_id)['results']['results']['conferences']
53
+
54
+ # is_for_mw_pr = html_url.include?('binmen') || html_url.include?('binwomen')
55
+
56
+ ## only rating page has conf standing tables
57
+ doc.search('div.laxcss a').remove ## remove team names from conf standing tables
58
+ @conf_standing_data = []
59
+ conf_standing_record = []
60
+ lines = doc.search('div.laxcs1, div.laxcss').text.lines
61
+
62
+ conf_data_index = 0
63
+ lines.each_with_index do |line, index|
64
+ if line.match /^\s[A-Z]/
65
+ if conf_standing_record.length > 0 ## it's a new conf standing table
66
+ @conf_standing_data << conf_standing_record
67
+ conf_standing_record = []
68
+ end
69
+
70
+ conf = conf_data[conf_data_index]
71
+
72
+ if conf.nil?
73
+ puts 'No independent conf data'
74
+ @conf_standing_data << conf_standing_record
75
+ break
76
+ end
77
+
78
+ conf_standing_record << [conf['state'], conf['teamClass'], conf['conference']]
79
+
80
+ conf_data_index += 1
81
+ elsif /^\s*\d+\s+/.match line
82
+ conf_standing_record << line.split(' ')
83
+ end
84
+
85
+ if (index == lines.length - 1)
86
+ @conf_standing_data << conf_standing_record
87
+ end
88
+ end
89
+ end
90
+
91
+ def get_response_from_mobile_api
92
+ HTTParty.post(api_url, headers: {'Content-Type' => 'application/json'}, body: api_body)
93
+ end
94
+
95
+ def get_response_from_mobile_api_with_params(url, body)
96
+ HTTParty.post(url, headers: {'Content-Type' => 'application/json'}, body: body)
97
+ end
98
+
99
+ def get_conference(season, category, div_id)
100
+ puts "get conference data for #{season}, #{category}, #{div_id} from " + DataValidation.api_request_host + '/rest/LaxPower/getConferences'
101
+ HTTParty.post(DataValidation.api_request_host + '/rest/LaxPower/getConferences',
102
+ headers: {'Content-Type' => 'application/json'},
103
+ body: %Q|{"season": "#{season}","category": "#{category}", "divisionId": #{div_id}}|)
104
+ end
105
+
106
+ def self.get_high_school_div_stat_urls(season='17', category='boys')
107
+ is_for_hs = category == 'boys' || category == 'girls'
108
+ high_school_div_stat_main_url = if is_for_hs
109
+ "#{DataValidation.web_request_host}/common/hs_#{category}.php"
110
+ else
111
+ "#{DataValidation.web_request_host}/common/college_#{category}.php"
112
+ end
113
+ doc = Nokogiri::HTML(open(high_school_div_stat_main_url))
114
+ urls = doc.search('div#content_well a[href*=rating]').map do |item|
115
+ href = item.attr('href')
116
+ if href.match /rating\d\d/
117
+ href.sub!('..', DataValidation.web_request_host)
118
+ href.sub!('update17', "update#{season}") if season!= '17'
119
+ href
120
+ end
121
+ end.compact
122
+
123
+ final_urls = [] + urls
124
+ ## append other metrics e.g. sos, rpi
125
+ if is_for_hs
126
+ %w|sos rpi wl qwf|.each { |stat_name| final_urls += replace_with_stat_name(urls, stat_name) }
127
+ else
128
+ %w|tsi poll rpi sos qwf trend|.each { |stat_name| final_urls += replace_with_stat_name(urls, stat_name) }
129
+ end
130
+ puts "totally #{final_urls.length} urls for #{season}, #{category}"
131
+ final_urls
132
+ end
133
+
134
+ def self.replace_with_stat_name urls, stat_name
135
+ urls.map do |url|
136
+ url.sub 'rating', stat_name
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,3 @@
1
+ module DataValidation
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,49 @@
1
+ require 'data_validation/comparison/comparison_factory'
2
+ require 'data_validation/data_access'
3
+ require 'yaml'
4
+
5
+ module DataValidation
6
+ class << self
7
+
8
+ def web_request_host
9
+ @web_request_host ||= begin
10
+ YAML.load_file('config/hosts.yml')['prod']['web_request_host']
11
+ end
12
+ end
13
+
14
+ def api_request_host
15
+ @api_request_host ||= begin
16
+ YAML.load_file('config/hosts.yml')['prod']['api_request_host']
17
+ end
18
+ end
19
+
20
+ def configure_with_env(env)
21
+ yaml_config = YAML.load_file('config/hosts.yml')
22
+ hash_config = yaml_config[env]
23
+ @web_request_host = hash_config['web_request_host']
24
+ @api_request_host = hash_config['api_request_host']
25
+ end
26
+
27
+ def compare_with_season_and_category(season = '17', category = 'boys')
28
+ web_urls = DataAccess.get_high_school_div_stat_urls season, category
29
+ web_urls.each do |url|
30
+ compare_with_url url
31
+ end
32
+ end
33
+
34
+ def compare_with_season(season = '17')
35
+ %w|men women boys girls|.each { |category| compare_with_season_and_category season, category }
36
+ end
37
+
38
+ def compare_with_url(url)
39
+ puts "Start validation of web url: #{url}"
40
+
41
+ comparison = DataValidation::Comparison::ComparisonFactory.get_comparison(url)
42
+ comparison.compare
43
+
44
+ puts "Complete validation of web url: #{url}"
45
+ puts '=============================='
46
+ end
47
+ end
48
+
49
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lx_data_validation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Roger Tong
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.6.6.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.6.6.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: httparty
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.8.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.8.1
83
+ description: The validation is to compare values between web page values and mobile
84
+ api responses
85
+ email:
86
+ - Roger.Tong@activenetwork.com
87
+ - tomtongt@live.com
88
+ executables:
89
+ - compare
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - ".rspec"
95
+ - ".travis.yml"
96
+ - Gemfile
97
+ - LICENSE.txt
98
+ - README.md
99
+ - Rakefile
100
+ - bin/compare
101
+ - config/hosts.yml
102
+ - data_validation.gemspec
103
+ - lib/data_validation.rb
104
+ - lib/data_validation/comparison/comparison_base.rb
105
+ - lib/data_validation/comparison/comparison_factory.rb
106
+ - lib/data_validation/comparison/conference_ranking_table_comparison.rb
107
+ - lib/data_validation/comparison/div_ranking_pr_comparison.rb
108
+ - lib/data_validation/comparison/div_ranking_wl_comparison.rb
109
+ - lib/data_validation/comparison/ranking_table_mw_poll_comparison.rb
110
+ - lib/data_validation/comparison/ranking_table_mw_pr_comparison.rb
111
+ - lib/data_validation/comparison/ranking_table_mw_qw_comparison.rb
112
+ - lib/data_validation/comparison/ranking_table_mw_rpi_comparison.rb
113
+ - lib/data_validation/comparison/ranking_table_mw_sos_comparison.rb
114
+ - lib/data_validation/comparison/ranking_table_mw_trend_comparison.rb
115
+ - lib/data_validation/comparison/ranking_table_mw_tsi_comparison.rb
116
+ - lib/data_validation/data_access.rb
117
+ - lib/data_validation/version.rb
118
+ homepage: https://gitlab.dev.activenetwork.com/rtong/data-validation-for-laxpower
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: 2.1.4
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.4.5
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Data validation for LaxPower
142
+ test_files: []
143
+ has_rdoc: