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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/indexing_bug.md +11 -0
  3. data/.github/ISSUE_TEMPLATE/new_dataset_request.md +22 -0
  4. data/.gitignore +2 -0
  5. data/.rubocop.yml +18 -0
  6. data/.rubocop_fixme.yml +10 -0
  7. data/CHANGELOG.md +12 -0
  8. data/Gemfile +1 -0
  9. data/Gemfile.lock +21 -15
  10. data/README.md +4 -0
  11. data/Rakefile +2 -1
  12. data/app/assets/stylesheets/qa_server/_home-page.scss +2 -2
  13. data/app/assets/stylesheets/qa_server/_styles.scss +4 -0
  14. data/app/controllers/qa_server/authority_list_controller.rb +3 -3
  15. data/app/controllers/qa_server/authority_validation_controller.rb +11 -12
  16. data/app/controllers/qa_server/check_status_controller.rb +6 -6
  17. data/app/controllers/qa_server/homepage_controller.rb +2 -2
  18. data/app/controllers/qa_server/monitor_status_controller.rb +32 -48
  19. data/app/controllers/qa_server/usage_controller.rb +2 -2
  20. data/app/loggers/qa_server/scenario_logger.rb +38 -42
  21. data/app/models/qa_server/authority_scenario.rb +1 -1
  22. data/app/models/qa_server/authority_status.rb +1 -0
  23. data/app/models/qa_server/authority_status_failure.rb +1 -0
  24. data/app/models/qa_server/scenario_run_history.rb +189 -0
  25. data/app/models/qa_server/scenario_run_registry.rb +34 -0
  26. data/app/models/qa_server/scenario_run_summary.rb +44 -0
  27. data/app/models/qa_server/scenarios.rb +15 -17
  28. data/app/models/qa_server/search_scenario.rb +4 -4
  29. data/app/models/qa_server/term_scenario.rb +2 -1
  30. data/app/presenters/qa_server/authority_list_presenter.rb +7 -6
  31. data/app/presenters/qa_server/check_status_presenter.rb +26 -16
  32. data/app/presenters/qa_server/monitor_status_presenter.rb +94 -38
  33. data/app/services/qa_server/authority_lister_service.rb +9 -9
  34. data/app/services/qa_server/authority_loader_service.rb +16 -15
  35. data/app/services/qa_server/authority_validator_service.rb +13 -13
  36. data/app/services/qa_server/database_migrator.rb +1 -0
  37. data/app/services/qa_server/scenarios_loader_service.rb +29 -27
  38. data/app/validators/qa_server/scenario_validator.rb +25 -35
  39. data/app/validators/qa_server/search_scenario_validator.rb +25 -18
  40. data/app/validators/qa_server/term_scenario_validator.rb +2 -1
  41. data/app/views/qa_server/check_status/index.html.erb +1 -1
  42. data/app/views/qa_server/homepage/index.html.erb +3 -3
  43. data/app/views/qa_server/monitor_status/index.html.erb +15 -10
  44. data/app/views/qa_server/usage/index.html.erb +4 -4
  45. data/app/views/shared/_footer.html.erb +1 -1
  46. data/config/routes.rb +1 -0
  47. data/lib/generators/qa_server/assets_generator.rb +1 -0
  48. data/lib/generators/qa_server/config_generator.rb +6 -0
  49. data/lib/generators/qa_server/install_generator.rb +1 -0
  50. data/lib/generators/qa_server/models_generator.rb +1 -0
  51. data/lib/generators/qa_server/templates/config/initializers/qa_server.rb +4 -0
  52. data/lib/generators/qa_server/templates/config/locales/qa_server.en.yml +1 -1
  53. data/lib/generators/qa_server/templates/db/migrate/20180807045549_create_scenario_run_registry.rb.erb +7 -0
  54. data/lib/generators/qa_server/templates/db/migrate/20180807045552_create_scenario_run_history.rb.erb +16 -0
  55. data/lib/generators/qa_server/templates/db/migrate/20180807045554_drop_unused_tables.rb.erb +6 -0
  56. data/lib/generators/qa_server/templates/db/migrate/20180809045552_add_indices_to_scenario_run_history.rb.erb +8 -0
  57. data/lib/qa_server/configuration.rb +6 -0
  58. data/lib/qa_server/engine.rb +10 -1
  59. data/lib/qa_server/version.rb +2 -1
  60. data/lib/qa_server.rb +19 -1
  61. data/lib/tasks/install.rake +1 -0
  62. data/lib/tasks/qa_server_tasks.rake +1 -0
  63. data/qa_server.gemspec +8 -5
  64. data/spec/rails_helper.rb +1 -0
  65. data/spec/spec_helper.rb +98 -98
  66. data/spec/test_app_templates/Gemfile.extra +2 -1
  67. data/tasks/qa_server_dev.rake +1 -0
  68. 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 historical_data [Array<Hash>] data for past failures
9
- def initialize(authority_count:, authority_status:, current_data:, historical_data:)
10
- @authority_count = authority_count
11
- @authority_status = authority_status
12
- @current_failures = current_data
13
- @history = historical_data
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
- @authority_status.dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
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
- AuthorityStatus.first.dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
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
- @current_failures.map { |f| f[:authority_name] }.uniq.count
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
- @authority_status.test_count
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
- tests_count - failing_tests_count
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
- @current_failures.count
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
- @current_failures
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
- # [ { days_failing: 1, authority_name: 'AGROVOC_DIRECT' },
83
- # { days_failing: 3, authority_name: 'AGROVOC_LD4L_CACHE' },
84
- # { days_failing: 0, authority_name: 'LOCNAMES_LD4L_CACHE' } ]
85
- def history
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
- # TODO: STUBED -- need check for history data
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
- private
22
-
23
- def self.list_terms(scenarios, status_log)
24
- scenarios.term_scenarios.each { |scenario| QaServer::TermScenarioValidator.new(scenario: scenario, status_log: status_log).log_without_running }
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
- def self.list_searches(scenarios, status_log)
28
- scenarios.search_scenarios.each { |scenario| QaServer::SearchScenarioValidator.new(scenario: scenario, status_log: status_log).log_without_running }
29
- end
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
- private
23
- def self.authority_key(authority_name)
24
- authority_name.upcase.to_sym
25
- end
22
+ def self.authority_key(authority_name)
23
+ authority_name.upcase.to_sym
24
+ end
25
+ private_class_method :authority_key
26
26
 
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: ScenarioValidator::FAIL,
32
- error_message: "Unable to load authority '#{authority_name}'; cause: UNKNOWN") unless authority.present?
33
- return nil
34
- end
35
- authority
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
- private
32
-
33
- def self.run_terms(scenarios, status_log, validation_type)
34
- scenarios.term_scenarios.each { |scenario| term_validator_class.new(scenario: scenario, status_log: status_log, validation_type: validation_type).run }
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,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'rails/generators/active_record'
2
3
 
3
4
  module QaServer
@@ -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
- private
29
-
30
- def self.load_authority(authority_name, status_log)
31
- AuthorityLoaderService.load(authority_name: authority_name, status_log: status_log)
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
- def self.scenarios_exist?(authority_name, status_log)
46
- return true if File.exists?(scenario_path(authority_name))
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: #{scenario_path} does not exist.")
50
- false
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
- def self.scenario_path(authority_name)
54
- File.join(::Rails.root, 'config', 'authorities', 'linked_data', 'scenarios', "#{authority_name.downcase}_validation.yml")
55
- end
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
- def log(status: nil, errmsg: nil, expected: nil, actual: nil, target: nil)
37
- status_log.add(authority_name: authority_name,
38
- status: status,
39
- validation_type: scenario_validation_type,
40
- subauth: subauthority_name,
41
- service: service,
42
- action: action,
43
- url: url,
44
- error_message: errmsg,
45
- expected: expected,
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
- begin
62
- results = yield if block_given?
63
- actual_size = results.to_s.length
64
- status = actual_size > min_expected_size ? PASS : UNKNOWN
65
- errmsg = (status == PASS) ? '' : "#{scenario_type_name.capitalize} scenario unknown status; cause: Results actual size (#{actual_size} < expected size (#{min_expected_size})"
66
- log(status: status, errmsg: errmsg)
67
- rescue Exception => e
68
- log(status: FAIL, errmsg: "Exception executing #{scenario_type_name} scenario; cause: #{e.message}")
69
- end
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'.freeze
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
- begin
42
- results = yield if block_given?
43
- if results.blank?
44
- log(status: UNKNOWN, errmsg: "Search position scenario failed; cause: no results found", expected: expected_by_position, target: subject_uri)
45
- return
46
- end
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.', expected: expected_by_position, actual: actual_position, target: subject_uri)
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", expected: scenario.expected_by_position, target: subject_uri)
81
- return nil
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'.freeze
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[:status_label] %></td>
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 has been created as part of the
5
- <a href="http://ld4l.org" target="_blank">LD4L Labs project</a>, and is operated by
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 a grant from the <a href="https://mellon.org/" target="_blank">Andrew W. Mellon Foundation</a>.</p>
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>