qa_server 0.1.99 → 1.0.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/.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>
|