qa_server 0.1.99 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/indexing_bug.md +11 -0
- data/.github/ISSUE_TEMPLATE/new_dataset_request.md +22 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +18 -0
- data/.rubocop_fixme.yml +10 -0
- data/CHANGELOG.md +12 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +21 -15
- data/README.md +4 -0
- data/Rakefile +2 -1
- data/app/assets/stylesheets/qa_server/_home-page.scss +2 -2
- data/app/assets/stylesheets/qa_server/_styles.scss +4 -0
- data/app/controllers/qa_server/authority_list_controller.rb +3 -3
- data/app/controllers/qa_server/authority_validation_controller.rb +11 -12
- data/app/controllers/qa_server/check_status_controller.rb +6 -6
- data/app/controllers/qa_server/homepage_controller.rb +2 -2
- data/app/controllers/qa_server/monitor_status_controller.rb +32 -48
- data/app/controllers/qa_server/usage_controller.rb +2 -2
- data/app/loggers/qa_server/scenario_logger.rb +38 -42
- data/app/models/qa_server/authority_scenario.rb +1 -1
- data/app/models/qa_server/authority_status.rb +1 -0
- data/app/models/qa_server/authority_status_failure.rb +1 -0
- data/app/models/qa_server/scenario_run_history.rb +189 -0
- data/app/models/qa_server/scenario_run_registry.rb +34 -0
- data/app/models/qa_server/scenario_run_summary.rb +44 -0
- data/app/models/qa_server/scenarios.rb +15 -17
- data/app/models/qa_server/search_scenario.rb +4 -4
- data/app/models/qa_server/term_scenario.rb +2 -1
- data/app/presenters/qa_server/authority_list_presenter.rb +7 -6
- data/app/presenters/qa_server/check_status_presenter.rb +26 -16
- data/app/presenters/qa_server/monitor_status_presenter.rb +94 -38
- data/app/services/qa_server/authority_lister_service.rb +9 -9
- data/app/services/qa_server/authority_loader_service.rb +16 -15
- data/app/services/qa_server/authority_validator_service.rb +13 -13
- data/app/services/qa_server/database_migrator.rb +1 -0
- data/app/services/qa_server/scenarios_loader_service.rb +29 -27
- data/app/validators/qa_server/scenario_validator.rb +25 -35
- data/app/validators/qa_server/search_scenario_validator.rb +25 -18
- data/app/validators/qa_server/term_scenario_validator.rb +2 -1
- data/app/views/qa_server/check_status/index.html.erb +1 -1
- data/app/views/qa_server/homepage/index.html.erb +3 -3
- data/app/views/qa_server/monitor_status/index.html.erb +15 -10
- data/app/views/qa_server/usage/index.html.erb +4 -4
- data/app/views/shared/_footer.html.erb +1 -1
- data/config/routes.rb +1 -0
- data/lib/generators/qa_server/assets_generator.rb +1 -0
- data/lib/generators/qa_server/config_generator.rb +6 -0
- data/lib/generators/qa_server/install_generator.rb +1 -0
- data/lib/generators/qa_server/models_generator.rb +1 -0
- data/lib/generators/qa_server/templates/config/initializers/qa_server.rb +4 -0
- data/lib/generators/qa_server/templates/config/locales/qa_server.en.yml +1 -1
- data/lib/generators/qa_server/templates/db/migrate/20180807045549_create_scenario_run_registry.rb.erb +7 -0
- data/lib/generators/qa_server/templates/db/migrate/20180807045552_create_scenario_run_history.rb.erb +16 -0
- data/lib/generators/qa_server/templates/db/migrate/20180807045554_drop_unused_tables.rb.erb +6 -0
- data/lib/generators/qa_server/templates/db/migrate/20180809045552_add_indices_to_scenario_run_history.rb.erb +8 -0
- data/lib/qa_server/configuration.rb +6 -0
- data/lib/qa_server/engine.rb +10 -1
- data/lib/qa_server/version.rb +2 -1
- data/lib/qa_server.rb +19 -1
- data/lib/tasks/install.rake +1 -0
- data/lib/tasks/qa_server_tasks.rake +1 -0
- data/qa_server.gemspec +8 -5
- data/spec/rails_helper.rb +1 -0
- data/spec/spec_helper.rb +98 -98
- data/spec/test_app_templates/Gemfile.extra +2 -1
- data/tasks/qa_server_dev.rake +1 -0
- metadata +49 -7
@@ -1,36 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'gruff'
|
5
|
+
|
1
6
|
# This presenter class provides all data needed by the view that monitors status of authorities.
|
2
7
|
module QaServer
|
3
|
-
class MonitorStatusPresenter
|
4
|
-
|
5
|
-
# @param authority_count [Integer] number of loaded authorities
|
6
|
-
# @param authority_status [AuthorityStatus] summary status of the latest run of test scenarios
|
8
|
+
class MonitorStatusPresenter # rubocop:disable Metrics/ClassLength
|
9
|
+
# @param current_summary [ScenarioRunSummary] summary status of the latest run of test scenarios
|
7
10
|
# @param current_data [Array<Hash>] current set of failures for the latest test run, if any
|
8
|
-
# @param
|
9
|
-
def initialize(
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
11
|
+
# @param historical_summary_data [Array<Hash>] summary of past failuring runs per authority to drive chart
|
12
|
+
def initialize(current_summary:, current_failure_data:, historical_summary_data:, performance_data:)
|
13
|
+
@current_summary = current_summary
|
14
|
+
@current_failure_data = current_failure_data
|
15
|
+
@historical_summary_data = historical_summary_data
|
16
|
+
@performance_data = performance_data
|
14
17
|
end
|
15
18
|
|
16
19
|
# @return [String] date of last test run
|
17
20
|
def last_updated
|
18
|
-
@
|
21
|
+
@current_summary.run_dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
|
19
22
|
end
|
20
23
|
|
21
24
|
# @return [String] date of first recorded test run
|
22
25
|
def first_updated
|
23
|
-
|
26
|
+
QaServer::ScenarioRunRegistry.first.dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
|
24
27
|
end
|
25
28
|
|
26
29
|
# @return [Integer] number of loaded authorities
|
27
30
|
def authorities_count
|
28
|
-
@authority_count
|
31
|
+
@current_summary.authority_count
|
29
32
|
end
|
30
33
|
|
31
34
|
# @return [Integer] number of authorities with failing tests in the latest test run
|
32
35
|
def failing_authorities_count
|
33
|
-
@
|
36
|
+
@current_failure_data.map { |f| f[:authority_name] }.uniq.count
|
34
37
|
end
|
35
38
|
|
36
39
|
# @return [String] css style class representing whether all tests passed or any failed
|
@@ -40,17 +43,17 @@ module QaServer
|
|
40
43
|
|
41
44
|
# @return [Integer] number of tests in the latest test run
|
42
45
|
def tests_count
|
43
|
-
@
|
46
|
+
@current_summary.total_scenario_count
|
44
47
|
end
|
45
48
|
|
46
49
|
# @return [Integer] number of passing tests in the latest test run
|
47
50
|
def passing_tests_count
|
48
|
-
|
51
|
+
@current_summary.passing_scenario_count
|
49
52
|
end
|
50
53
|
|
51
54
|
# @return [Integer] number of failing tests in the latest test run
|
52
55
|
def failing_tests_count
|
53
|
-
@
|
56
|
+
@current_summary.failing_scenario_count
|
54
57
|
end
|
55
58
|
|
56
59
|
# @return [String] css style class representing whether all tests passed or any failed
|
@@ -69,7 +72,7 @@ module QaServer
|
|
69
72
|
# url: '/qa/search/linked_data/locnames_ld4l_cache/person?q=mark twain&maxRecords=4',
|
70
73
|
# err_message: 'Exception: Something went wrong.' }, ... ]
|
71
74
|
def failures
|
72
|
-
@
|
75
|
+
@current_failure_data
|
73
76
|
end
|
74
77
|
|
75
78
|
# @return [Boolean] true if failure data exists for the latest test run; otherwise false
|
@@ -77,32 +80,85 @@ module QaServer
|
|
77
80
|
failing_tests_count.positive?
|
78
81
|
end
|
79
82
|
|
80
|
-
# @return [Array<Hash>] historical test data to be displayed
|
83
|
+
# @return [Array<Hash>] historical test data to be displayed (authname, failing, passing)
|
81
84
|
# @example
|
82
|
-
# [
|
83
|
-
#
|
84
|
-
|
85
|
-
|
86
|
-
# TODO: STUBED -- need to include history of past failures -- Question: How much data to save?
|
87
|
-
# Want to answer questions like...
|
88
|
-
# * # of failing days out of # of days run
|
89
|
-
# * # type of failures... can't load authority vs. exception vs. no data returned
|
90
|
-
# * for a given authority, did all tests fail or just a few?
|
91
|
-
# * are tests failing for a particular subauthority?
|
92
|
-
# * are tests failing for a particular type (search vs. term)
|
93
|
-
history = []
|
94
|
-
entry = { days_failing: 3,
|
95
|
-
authority_name: "FOO",
|
96
|
-
subauthority_name: "bar",
|
97
|
-
service: 'test',
|
98
|
-
action: 'search' }
|
99
|
-
history << entry
|
85
|
+
# [ [ 'agrovoc', 0, 24 ],
|
86
|
+
# [ 'geonames_ld4l_cache', 2, 22 ] ... ]
|
87
|
+
def historical_summary
|
88
|
+
@historical_summary_data
|
100
89
|
end
|
101
90
|
|
102
91
|
# @return [Boolean] true if historical test data exists; otherwise false
|
103
92
|
def history?
|
104
|
-
|
93
|
+
return true if @historical_summary_data.present?
|
105
94
|
false
|
106
95
|
end
|
96
|
+
|
97
|
+
def historical_graph
|
98
|
+
# g = Gruff::SideStackedBar.new('800x400')
|
99
|
+
g = Gruff::SideStackedBar.new
|
100
|
+
graph_theme(g)
|
101
|
+
g.title = ''
|
102
|
+
historical_data = rework_historical_data_for_gruff
|
103
|
+
g.labels = historical_data[0]
|
104
|
+
g.data('Fail', historical_data[1])
|
105
|
+
g.data('Pass', historical_data[2])
|
106
|
+
g.write historical_graph_full_path
|
107
|
+
File.join(historical_graph_relative_path, historical_graph_filename)
|
108
|
+
end
|
109
|
+
|
110
|
+
# @return [String] the name of the css style class to use for the status cell based on the status of the scenario test.
|
111
|
+
def status_style_class(status)
|
112
|
+
"status-#{status[:status]}"
|
113
|
+
end
|
114
|
+
|
115
|
+
# @return [String] the name of the css style class to use for the status cell based on the status of the scenario test.
|
116
|
+
def status_label(status)
|
117
|
+
case status[:status]
|
118
|
+
when :good
|
119
|
+
QaServer::ScenarioRunHistory::GOOD_MARKER
|
120
|
+
when :bad
|
121
|
+
QaServer::ScenarioRunHistory::BAD_MARKER
|
122
|
+
when :unknown
|
123
|
+
QaServer::ScenarioRunHistory::UNKNOWN_MARKER
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def graph_theme(g)
|
130
|
+
g.theme_pastel
|
131
|
+
g.colors = ['#ffcccc', '#ccffcc']
|
132
|
+
g.marker_font_size = 12
|
133
|
+
g.x_axis_increment = 10
|
134
|
+
end
|
135
|
+
|
136
|
+
def historical_graph_full_path
|
137
|
+
path = Rails.root.join('app', 'assets', 'images', historical_graph_relative_path)
|
138
|
+
FileUtils.mkdir_p path
|
139
|
+
File.join(path, historical_graph_filename)
|
140
|
+
end
|
141
|
+
|
142
|
+
def historical_graph_relative_path
|
143
|
+
File.join('qa_server', 'charts')
|
144
|
+
end
|
145
|
+
|
146
|
+
def historical_graph_filename
|
147
|
+
'historical_side_stacked_bar.png'
|
148
|
+
end
|
149
|
+
|
150
|
+
def rework_historical_data_for_gruff
|
151
|
+
labels = {}
|
152
|
+
pass_data = []
|
153
|
+
fail_data = []
|
154
|
+
i = 0
|
155
|
+
historical_summary.each do |data|
|
156
|
+
labels[i] = data[0]
|
157
|
+
i += 1
|
158
|
+
fail_data << data[1]
|
159
|
+
pass_data << data[2]
|
160
|
+
end
|
161
|
+
[labels, fail_data, pass_data]
|
162
|
+
end
|
107
163
|
end
|
108
164
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# Provide service methods for getting a list of all authorities and scenarios for an authority.
|
2
3
|
module QaServer
|
3
4
|
class AuthorityListerService
|
4
|
-
|
5
5
|
# Return a list of supported authorities
|
6
6
|
# @return [Array<String>] list of authorities
|
7
7
|
def self.authorities_list
|
@@ -18,14 +18,14 @@ module QaServer
|
|
18
18
|
list_searches(scenarios, status_log)
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
21
|
+
def self.list_terms(scenarios, status_log)
|
22
|
+
scenarios.term_scenarios.each { |scenario| QaServer::TermScenarioValidator.new(scenario: scenario, status_log: status_log).log_without_running }
|
23
|
+
end
|
24
|
+
private_class_method :list_terms
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
def self.list_searches(scenarios, status_log)
|
27
|
+
scenarios.search_scenarios.each { |scenario| QaServer::SearchScenarioValidator.new(scenario: scenario, status_log: status_log).log_without_running }
|
28
|
+
end
|
29
|
+
private_class_method :list_searches
|
30
30
|
end
|
31
31
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# This class loads an authority.
|
2
3
|
module QaServer
|
3
4
|
class AuthorityLoaderService
|
4
|
-
|
5
5
|
# Load a QA authority
|
6
6
|
# @param authority_name [String] name of the authority to load (e.g. "agrovoc_direct")
|
7
7
|
# @param status_log [ScenarioLogger] logger to hold failure information if the authority cannot be loaded
|
@@ -12,27 +12,28 @@ module QaServer
|
|
12
12
|
return nil if authority.blank?
|
13
13
|
rescue Exception => e
|
14
14
|
status_log.add(authority_name: authority_name,
|
15
|
-
status: ScenarioValidator::FAIL,
|
15
|
+
status: QaServer::ScenarioValidator::FAIL,
|
16
16
|
error_message: "Unable to load authority '#{authority_name}'; cause: #{e.message}")
|
17
17
|
return nil
|
18
18
|
end
|
19
19
|
authority
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
def self.authority_key(authority_name)
|
23
|
+
authority_name.upcase.to_sym
|
24
|
+
end
|
25
|
+
private_class_method :authority_key
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
27
|
+
def self.load_authority(authority_name, status_log)
|
28
|
+
authority = Qa::Authorities::LinkedData::GenericAuthority.new(authority_key(authority_name))
|
29
|
+
if authority.blank?
|
30
|
+
status_log.add(authority_name: authority_name,
|
31
|
+
status: QaServer::ScenarioValidator::FAIL,
|
32
|
+
error_message: "Unable to load authority '#{authority_name}'; cause: UNKNOWN")
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
authority
|
36
36
|
end
|
37
|
+
private_class_method :load_authority
|
37
38
|
end
|
38
39
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# Provide service methods for running a a set of validation scenarios for an authority.
|
2
3
|
module QaServer
|
3
4
|
class AuthorityValidatorService
|
@@ -6,10 +7,10 @@ module QaServer
|
|
6
7
|
:search_validator_class,
|
7
8
|
:scenarios_loader_class
|
8
9
|
|
9
|
-
self.validator_class = ScenarioValidator
|
10
|
-
self.term_validator_class = TermScenarioValidator
|
11
|
-
self.search_validator_class = SearchScenarioValidator
|
12
|
-
self.scenarios_loader_class = ScenariosLoaderService
|
10
|
+
self.validator_class = QaServer::ScenarioValidator
|
11
|
+
self.term_validator_class = QaServer::TermScenarioValidator
|
12
|
+
self.search_validator_class = QaServer::SearchScenarioValidator
|
13
|
+
self.scenarios_loader_class = QaServer::ScenariosLoaderService
|
13
14
|
|
14
15
|
VALIDATE_CONNECTIONS = validator_class::VALIDATE_CONNECTION
|
15
16
|
VALIDATE_ACCURACY = validator_class::VALIDATE_ACCURACY
|
@@ -27,15 +28,14 @@ module QaServer
|
|
27
28
|
run_searches(scenarios, status_log, validation_type)
|
28
29
|
end
|
29
30
|
|
31
|
+
def self.run_terms(scenarios, status_log, validation_type)
|
32
|
+
scenarios.term_scenarios.each { |scenario| term_validator_class.new(scenario: scenario, status_log: status_log, validation_type: validation_type).run }
|
33
|
+
end
|
34
|
+
private_class_method :run_terms
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.run_searches(scenarios, status_log, validation_type)
|
38
|
-
scenarios.search_scenarios.each { |scenario| search_validator_class.new(scenario: scenario, status_log: status_log, validation_type: validation_type).run }
|
39
|
-
end
|
36
|
+
def self.run_searches(scenarios, status_log, validation_type)
|
37
|
+
scenarios.search_scenarios.each { |scenario| search_validator_class.new(scenario: scenario, status_log: status_log, validation_type: validation_type).run }
|
38
|
+
end
|
39
|
+
private_class_method :run_searches
|
40
40
|
end
|
41
41
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# This class loads scenario configuration file for an authority.
|
2
3
|
module QaServer
|
3
4
|
class ScenariosLoaderService
|
4
|
-
|
5
5
|
# Load scenarios for testing an authority
|
6
6
|
# @param authority_name [String] name of the authority to load (e.g. "agrovoc_direct")
|
7
7
|
# @param status_log [ScenarioLogger] logger to hold failure information if the scenarios cannot be loaded
|
@@ -15,43 +15,45 @@ module QaServer
|
|
15
15
|
scenarios_config = load_config(authority_name, status_log)
|
16
16
|
return nil if scenarios_config.blank?
|
17
17
|
|
18
|
-
scenarios = Scenarios.new(authority: authority, authority_name: authority_name, scenarios_config: scenarios_config)
|
18
|
+
scenarios = QaServer::Scenarios.new(authority: authority, authority_name: authority_name, scenarios_config: scenarios_config)
|
19
19
|
rescue Exception => e
|
20
20
|
status_log.add(authority_name: authority_name,
|
21
|
-
status: ScenarioValidator::FAIL,
|
21
|
+
status: QaServer::ScenarioValidator::FAIL,
|
22
22
|
error_message: "Unable to load scenarios for authority '#{authority_name}'; cause: #{e.message}")
|
23
23
|
return nil
|
24
24
|
end
|
25
25
|
scenarios
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.load_config(authority_name, status_log)
|
35
|
-
scenarios_config = YAML.load_file(scenario_path(authority_name))
|
36
|
-
unless scenarios_config.present?
|
37
|
-
status_log.add(authority_name: authority_name,
|
38
|
-
status: ScenarioValidator::FAIL,
|
39
|
-
error_message: "Unable to load scenarios for authority '#{authority_name}'; cause: UNKNOWN")
|
40
|
-
return nil
|
41
|
-
end
|
42
|
-
scenarios_config
|
43
|
-
end
|
28
|
+
def self.load_authority(authority_name, status_log)
|
29
|
+
QaServer::AuthorityLoaderService.load(authority_name: authority_name, status_log: status_log)
|
30
|
+
end
|
31
|
+
private_class_method :load_authority
|
44
32
|
|
45
|
-
|
46
|
-
|
33
|
+
def self.load_config(authority_name, status_log)
|
34
|
+
scenarios_config = YAML.load_file(scenario_path(authority_name))
|
35
|
+
unless scenarios_config.present?
|
47
36
|
status_log.add(authority_name: authority_name,
|
48
|
-
status: ScenarioValidator::FAIL,
|
49
|
-
error_message: "Unable to load scenarios for authority '#{authority_name}'; cause:
|
50
|
-
|
37
|
+
status: QaServer::ScenarioValidator::FAIL,
|
38
|
+
error_message: "Unable to load scenarios for authority '#{authority_name}'; cause: UNKNOWN")
|
39
|
+
return nil
|
51
40
|
end
|
41
|
+
scenarios_config
|
42
|
+
end
|
43
|
+
private_class_method :load_config
|
44
|
+
|
45
|
+
def self.scenarios_exist?(authority_name, status_log)
|
46
|
+
return true if File.exist?(scenario_path(authority_name))
|
47
|
+
status_log.add(authority_name: authority_name,
|
48
|
+
status: QaServer::ScenarioValidator::FAIL,
|
49
|
+
error_message: "Unable to load scenarios for authority '#{authority_name}'; cause: #{scenario_path} does not exist.")
|
50
|
+
false
|
51
|
+
end
|
52
|
+
private_class_method :scenarios_exist?
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
def self.scenario_path(authority_name)
|
55
|
+
File.join(::Rails.root, 'config', 'authorities', 'linked_data', 'scenarios', "#{authority_name.downcase}_validation.yml")
|
56
|
+
end
|
57
|
+
private_class_method :scenario_path
|
56
58
|
end
|
57
59
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# ABSTRACT class providing common methods for running a scenario of any type.
|
2
3
|
module QaServer
|
3
4
|
class ScenarioValidator
|
@@ -10,6 +11,8 @@ module QaServer
|
|
10
11
|
ALL_VALIDATIONS = :all_validations
|
11
12
|
DEFAULT_VALIDATION_TYPE = VALIDATE_CONNECTION
|
12
13
|
|
14
|
+
attr_reader :status_log, :scenario, :validation_type
|
15
|
+
|
13
16
|
# @param scenario [SearchScenario | TermScenario] the scenario to run
|
14
17
|
# @param status_log [ScenarioLogger] logger for recording test results
|
15
18
|
# @param validation_type [Symbol] the type of scenarios to run (e.g. VALIDATE_CONNECTION, VALIDATE_ACCURACY, ALL_VALIDATIONS)
|
@@ -33,18 +36,16 @@ module QaServer
|
|
33
36
|
private
|
34
37
|
|
35
38
|
# Log the structure of the scenario and status of a test run.
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
actual: actual,
|
47
|
-
target: target)
|
39
|
+
# @param [Hash] status_info holding information to be logged
|
40
|
+
# @see QaServer::ScenarioLogger
|
41
|
+
def log(status_info = {})
|
42
|
+
status_info[:authority_name] = authority_name
|
43
|
+
status_info[:validation_type] = scenario_validation_type
|
44
|
+
status_info[:subauth] = subauthority_name
|
45
|
+
status_info[:service] = service
|
46
|
+
status_info[:action] = action
|
47
|
+
status_info[:url] = url
|
48
|
+
status_log.add(status_info)
|
48
49
|
end
|
49
50
|
|
50
51
|
def run_accuracy_scenario
|
@@ -58,15 +59,16 @@ module QaServer
|
|
58
59
|
# Runs the test in the block passed by the specific scenario type.
|
59
60
|
# @return [Symbol] :good (PASS) or :unknown (UNKNOWN) based on whether enough results were returned
|
60
61
|
def test_connection(min_expected_size: MIN_EXPECTED_SIZE, scenario_type_name:)
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
62
|
+
dt_start = Time.now.utc
|
63
|
+
results = yield if block_given?
|
64
|
+
dt_end = Time.now.utc
|
65
|
+
actual_size = results.to_s.length
|
66
|
+
status = actual_size > min_expected_size ? PASS : UNKNOWN
|
67
|
+
errmsg = status == PASS ? '' : "#{scenario_type_name.capitalize} scenario unknown status; cause: Results actual size (#{actual_size} < expected size (#{min_expected_size})"
|
68
|
+
log(status: status, errmsg: errmsg, normalization_run_time: (dt_end - dt_start)) # TODO: need to get run times from results
|
69
|
+
rescue Exception => e
|
70
|
+
dt_end = Time.now.utc
|
71
|
+
log(status: FAIL, errmsg: "Exception executing #{scenario_type_name} scenario; cause: #{e.message}", request_run_time: (dt_end - dt_start))
|
70
72
|
end
|
71
73
|
|
72
74
|
def authority
|
@@ -93,18 +95,6 @@ module QaServer
|
|
93
95
|
# ABSTRACT - must be implemented by scenario validator for specific types
|
94
96
|
end
|
95
97
|
|
96
|
-
def status_log
|
97
|
-
@status_log
|
98
|
-
end
|
99
|
-
|
100
|
-
def scenario
|
101
|
-
@scenario
|
102
|
-
end
|
103
|
-
|
104
|
-
def validation_type
|
105
|
-
@validation_type
|
106
|
-
end
|
107
|
-
|
108
98
|
def scenario_validation_type
|
109
99
|
return VALIDATE_CONNECTION if connection_scenario?
|
110
100
|
return VALIDATE_ACCURACY if accuracy_scenario?
|
@@ -122,12 +112,12 @@ module QaServer
|
|
122
112
|
end
|
123
113
|
|
124
114
|
def accuracy_scenario?
|
125
|
-
# ABSTRACT define in specific scenario type validator (i.e. TermScenarioValidator, SearchScenarioValidator)
|
115
|
+
# ABSTRACT define in specific scenario type validator (i.e. QaServer::TermScenarioValidator, QaServer::SearchScenarioValidator)
|
126
116
|
false
|
127
117
|
end
|
128
118
|
|
129
119
|
def connection_scenario?
|
130
|
-
# ABSTRACT define in specific scenario type validator (i.e. TermScenarioValidator, SearchScenarioValidator)
|
120
|
+
# ABSTRACT define in specific scenario type validator (i.e. QaServer::TermScenarioValidator, QaServer::SearchScenarioValidator)
|
131
121
|
false
|
132
122
|
end
|
133
123
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'json'
|
2
3
|
|
3
4
|
# This class runs a single search scenario and logs the results.
|
4
5
|
module QaServer
|
5
6
|
class SearchScenarioValidator < ScenarioValidator
|
6
|
-
SEARCH_ACTION = 'search'
|
7
|
+
SEARCH_ACTION = 'search'
|
7
8
|
|
8
9
|
# @param scenario [SearchScenario] the scenario to run
|
9
10
|
# @param status_log [ScenarioLogger] logger for recording test results
|
@@ -38,17 +39,19 @@ module QaServer
|
|
38
39
|
|
39
40
|
# Runs the accuracy test and log results
|
40
41
|
def test_accuracy(subject_uri:, expected_by_position:)
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
check_position(results, subject_uri, expected_by_position)
|
49
|
-
rescue Exception => e
|
50
|
-
log(status: FAIL, errmsg: "Exception executing search position scenario; cause: #{e.message}", expected: expected_by_position, target: subject_uri)
|
42
|
+
dt_start = Time.now.utc
|
43
|
+
results = yield if block_given?
|
44
|
+
dt_end = Time.now.utc
|
45
|
+
if results.blank?
|
46
|
+
log(status: UNKNOWN, errmsg: "Search position scenario failed; cause: no results found", expected: expected_by_position, target: subject_uri, request_run_time: (dt_end - dt_start))
|
47
|
+
return
|
51
48
|
end
|
49
|
+
|
50
|
+
check_position(results, subject_uri, expected_by_position, total_run_time: (dt_end - dt_start)) # TODO: need to get run times from results
|
51
|
+
rescue Exception => e
|
52
|
+
dt_end = Time.now.utc
|
53
|
+
log(status: FAIL, errmsg: "Exception executing search position scenario; cause: #{e.message}",
|
54
|
+
expected: expected_by_position, target: subject_uri, request_run_time: (dt_end - dt_start))
|
52
55
|
end
|
53
56
|
|
54
57
|
def accuracy_scenario?
|
@@ -61,24 +64,28 @@ module QaServer
|
|
61
64
|
!accuracy_scenario?
|
62
65
|
end
|
63
66
|
|
64
|
-
def check_position(results, subject_uri, expected_by_position)
|
65
|
-
actual_position = subject_position(results, subject_uri)
|
67
|
+
def check_position(results, subject_uri, expected_by_position, total_run_time)
|
68
|
+
actual_position = subject_position(results, subject_uri, total_run_time)
|
66
69
|
return if actual_position.blank?
|
67
70
|
|
68
71
|
actual_position += 1
|
69
72
|
if actual_position <= expected_by_position
|
70
|
-
log(status: PASS, expected: expected_by_position, actual: actual_position, target: subject_uri
|
73
|
+
log(status: PASS, expected: expected_by_position, actual: actual_position, target: subject_uri,
|
74
|
+
normalization_run_time: run_time) # TODO: need to get run times from results
|
71
75
|
else
|
72
|
-
log(status: UNKNOWN, errmsg: 'Subject URI not found by the expected position.',
|
76
|
+
log(status: UNKNOWN, errmsg: 'Subject URI not found by the expected position.',
|
77
|
+
expected: expected_by_position, actual: actual_position, target: subject_uri,
|
78
|
+
normalization_run_time: total_run_time) # TODO: need to get run times from results
|
73
79
|
end
|
74
80
|
end
|
75
81
|
|
76
|
-
def subject_position(results, subject_uri)
|
82
|
+
def subject_position(results, subject_uri, total_run_time)
|
77
83
|
0.upto(results.size - 1) do |position|
|
78
84
|
return position if results[position][:uri] == subject_uri
|
79
85
|
end
|
80
|
-
log(status: UNKNOWN, errmsg: "Search position scenario failed; cause: subject uri (#{subject_uri}) not found in results",
|
81
|
-
|
86
|
+
log(status: UNKNOWN, errmsg: "Search position scenario failed; cause: subject uri (#{subject_uri}) not found in results",
|
87
|
+
expected: scenario.expected_by_position, target: subject_uri, normalization_run_time: total_run_time) # TODO: need to get run times from results
|
88
|
+
nil
|
82
89
|
end
|
83
90
|
end
|
84
91
|
end
|
@@ -1,7 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
# This class runs a single term scenario and logs the results.
|
2
3
|
module QaServer
|
3
4
|
class TermScenarioValidator < ScenarioValidator
|
4
|
-
TERM_ACTION = 'term'
|
5
|
+
TERM_ACTION = 'term'
|
5
6
|
|
6
7
|
# @param scenario [TermScenario] the scenario to run
|
7
8
|
# @param status_log [ScenarioLogger] logger for recording test results
|
@@ -56,7 +56,7 @@
|
|
56
56
|
</tr>
|
57
57
|
<% @presenter.connection_status_data.each do |status| %>
|
58
58
|
<tr>
|
59
|
-
<td class="<%= @presenter.status_style_class(status) %>"><%= status
|
59
|
+
<td class="<%= @presenter.status_style_class(status) %>"><%= @presenter.status_label(status) %></td>
|
60
60
|
<td><%= status[:authority_name] %></td>
|
61
61
|
<td><%= status[:subauthority_name] %></td>
|
62
62
|
<td><%= status[:service] %></td>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<div class="page-description">
|
2
2
|
<p class="welcome">This service provides authority <b>lookup for single terms</b> and <b>search for terms</b> matching a query.
|
3
3
|
See <a href="<%= "#{main_app.root_path}usage" %>">Usage</a> for more information.</p>
|
4
|
-
<p class="welcome2">It
|
5
|
-
<a href="http://ld4l.org" target="_blank">
|
4
|
+
<p class="welcome2">It was created as part of the
|
5
|
+
<a href="http://ld4l.org" target="_blank">Linked Data for Libraries - Labs</a> project and continues to be supported by the <a href="https://wiki.duraspace.org/x/9xgRBg" class="navbar-link" target="_blank">Linked Data for Production</a> project. It is operated by
|
6
6
|
<a href="http://www.library.cornell.edu/" target="_blank">Cornell University Library</a>
|
7
7
|
in collaboration with the
|
8
8
|
<a href="https://www.slis.uiowa.edu/" target="_blank">School of Library and Information Science, University of Iowa</a>.
|
9
|
-
This work was funded through
|
9
|
+
This work was funded through grants from the <a href="https://mellon.org/" target="_blank">Andrew W. Mellon Foundation</a>.</p>
|
10
10
|
</div>
|