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.
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>