qa_server 7.2.0 → 7.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop_fixme.yml +6 -0
  3. data/.travis.yml +4 -5
  4. data/CHANGELOG.md +38 -0
  5. data/Rakefile +1 -1
  6. data/app/assets/stylesheets/qa_server/_check-status.scss +36 -0
  7. data/app/cache_processors/concerns/qa_server/cache_keys.rb +0 -5
  8. data/app/cache_processors/qa_server/cache_expiry_service.rb +13 -8
  9. data/app/cache_processors/qa_server/job_id_cache.rb +29 -0
  10. data/app/cache_processors/qa_server/performance_cache.rb +34 -34
  11. data/app/cache_processors/qa_server/performance_day_graph_cache.rb +27 -0
  12. data/app/cache_processors/qa_server/performance_month_graph_cache.rb +27 -0
  13. data/app/cache_processors/qa_server/performance_year_graph_cache.rb +27 -0
  14. data/app/cache_processors/qa_server/scenario_history_cache.rb +7 -7
  15. data/app/cache_processors/qa_server/scenario_history_graph_cache.rb +12 -17
  16. data/app/cache_processors/qa_server/scenario_run_cache.rb +8 -8
  17. data/app/cache_processors/qa_server/scenario_run_failures_cache.rb +7 -7
  18. data/app/cache_processors/qa_server/scenario_run_summary_cache.rb +7 -7
  19. data/app/controllers/concerns/qa_server/authority_validation_behavior.rb +49 -44
  20. data/app/controllers/qa_server/check_status_controller.rb +92 -22
  21. data/app/controllers/qa_server/fetch_controller.rb +36 -36
  22. data/app/controllers/qa_server/monitor_status_controller.rb +105 -105
  23. data/app/jobs/qa_server/history_graph_job.rb +28 -0
  24. data/app/jobs/qa_server/monitor_tests_job.rb +19 -39
  25. data/app/jobs/qa_server/performance_day_graph_job.rb +45 -0
  26. data/app/jobs/qa_server/performance_month_graph_job.rb +45 -0
  27. data/app/jobs/qa_server/performance_per_byte_job.rb +85 -0
  28. data/app/jobs/qa_server/performance_year_graph_job.rb +45 -0
  29. data/app/loggers/qa_server/scenario_logger.rb +74 -4
  30. data/app/models/concerns/qa_server/performance_history_data_keys.rb +8 -0
  31. data/app/models/qa_server/authority_scenario.rb +4 -4
  32. data/app/models/qa_server/authority_status.rb +2 -2
  33. data/app/models/qa_server/authority_status_failure.rb +1 -1
  34. data/app/models/qa_server/performance_history.rb +2 -2
  35. data/app/models/qa_server/scenario_run_history.rb +52 -52
  36. data/app/models/qa_server/scenario_run_registry.rb +2 -2
  37. data/app/models/qa_server/scenarios.rb +26 -26
  38. data/app/models/qa_server/search_scenario.rb +18 -13
  39. data/app/models/qa_server/term_scenario.rb +29 -29
  40. data/app/prepends/prepended_linked_data/find_term.rb +40 -40
  41. data/app/prepends/prepended_linked_data/search_query.rb +36 -36
  42. data/app/prepends/prepended_rdf/rdf_graph.rb +7 -7
  43. data/app/presenters/concerns/qa_server/monitor_status/performance_datatable_behavior.rb +32 -32
  44. data/app/presenters/concerns/qa_server/monitor_status/performance_graph_behavior.rb +64 -64
  45. data/app/presenters/qa_server/check_status_presenter.rb +63 -7
  46. data/app/services/concerns/qa_server/gruff_graph.rb +16 -16
  47. data/app/services/qa_server/authority_loader_service.rb +14 -14
  48. data/app/services/qa_server/authority_validator_service.rb +1 -0
  49. data/app/services/qa_server/database_migrator.rb +14 -14
  50. data/app/services/qa_server/history_graphing_service.rb +30 -30
  51. data/app/services/qa_server/performance_calculator_service.rb +80 -80
  52. data/app/services/qa_server/performance_datatable_service.rb +35 -35
  53. data/app/services/qa_server/performance_graph_data_service.rb +28 -28
  54. data/app/services/qa_server/performance_graphing_service.rb +58 -58
  55. data/app/services/qa_server/performance_per_byte_calculator_service.rb +88 -0
  56. data/app/services/qa_server/performance_per_byte_data_service.rb +41 -0
  57. data/app/services/qa_server/scenarios_loader_service.rb +1 -1
  58. data/app/services/qa_server/time_period_service.rb +21 -21
  59. data/app/validators/qa_server/scenario_validator.rb +99 -87
  60. data/app/validators/qa_server/search_scenario_validator.rb +67 -61
  61. data/app/validators/qa_server/term_scenario_validator.rb +20 -15
  62. data/app/views/qa_server/check_status/index.html.erb +120 -24
  63. data/config/i18n-tasks.yml +133 -0
  64. data/config/locales/qa_server.en.yml +15 -0
  65. data/lib/generators/qa_server/assets_generator.rb +4 -4
  66. data/lib/generators/qa_server/templates/config/authorities/linked_data/cerl_ld4l_cache.json +2 -2
  67. data/lib/generators/qa_server/templates/config/authorities/linked_data/getty_aat_ld4l_cache.json +62 -1
  68. data/lib/generators/qa_server/templates/config/authorities/linked_data/getty_tgn_ld4l_cache.json +28 -4
  69. data/lib/generators/qa_server/templates/config/authorities/linked_data/isni_ld4l_cache.json +90 -0
  70. data/lib/generators/qa_server/templates/config/authorities/linked_data/ligatus_ld4l_cache.json +133 -0
  71. data/lib/generators/qa_server/templates/config/authorities/linked_data/locnames_rwo2_ld4l_cache.json +248 -0
  72. data/lib/generators/qa_server/templates/config/authorities/linked_data/locnames_rwo3_ld4l_cache.json +248 -0
  73. data/lib/generators/qa_server/templates/config/authorities/linked_data/locvocabs_ld4l_cache.json +117 -0
  74. data/lib/generators/qa_server/templates/config/authorities/linked_data/mesh_nlm_ld4l_cache.json +135 -3
  75. data/lib/generators/qa_server/templates/config/authorities/linked_data/oclcfast_direct.json +1 -0
  76. data/lib/generators/qa_server/templates/config/authorities/linked_data/oclcfast_ld4l_cache.json +1 -4
  77. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/agrovoc_direct_validation.yml +31 -0
  78. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/agrovoc_ld4l_cache_validation.yml +31 -0
  79. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/cerl_ld4l_cache_validation.yml +23 -11
  80. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/dbpedia_ld4l_cache_validation.yml +33 -0
  81. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/geonames_direct_validation.yml +35 -0
  82. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/geonames_ld4l_cache_validation.yml +58 -5
  83. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/getty_aat_ld4l_cache_validation.yml +256 -0
  84. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/getty_tgn_ld4l_cache_validation.yml +35 -1
  85. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/getty_ulan_ld4l_cache_validation.yml +37 -0
  86. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/isni_ld4l_cache_validation.yml +10 -0
  87. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/ligatus_ld4l_cache_validation.yml +36 -0
  88. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locdemographics_ld4l_cache_validation.yml +73 -44
  89. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locgenres_ld4l_cache_validation.yml +31 -0
  90. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locnames_ld4l_cache_validation.yml +71 -0
  91. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locnames_rwo_ld4l_cache_validation.yml +70 -2
  92. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locperformance_ld4l_cache_validation.yml +6 -0
  93. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locsubjects_ld4l_cache_validation.yml +32 -0
  94. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/locvocabs_ld4l_cache_validation.yml +184 -0
  95. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/mesh_nlm_ld4l_cache_validation.yml +51 -1
  96. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/nalt_ld4l_cache_validation.yml +37 -0
  97. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/oclc_fast_validation.yml +71 -5
  98. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/oclcfast_direct_validation.yml +66 -1
  99. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/oclcfast_ld4l_cache_validation.yml +57 -0
  100. data/lib/generators/qa_server/templates/config/authorities/linked_data/scenarios/rda_registry_ld4l_cache_validation.yml +310 -0
  101. data/lib/qa_server/configuration.rb +28 -24
  102. data/lib/qa_server/version.rb +1 -1
  103. data/qa_server.gemspec +2 -1
  104. data/spec/feature/accuracy_spec.rb +32 -0
  105. data/spec/i18n_spec.rb +36 -0
  106. data/spec/spec_helper.rb +4 -0
  107. metadata +46 -12
  108. data/app/cache_processors/qa_server/performance_daily_graph_cache.rb +0 -60
  109. data/app/cache_processors/qa_server/performance_hourly_graph_cache.rb +0 -65
  110. data/app/cache_processors/qa_server/performance_monthly_graph_cache.rb +0 -60
@@ -73,7 +73,7 @@ module QaServer
73
73
  # @param authority_name [String] name of an authority
74
74
  # @param action [Symbol] :search, :fetch, or :all_actions
75
75
  # @param averages [Hash] existing data for each hour
76
- # @returns [Hash] existing hourly data with the last hour updated
76
+ # @returns [Hash] existing day data with the last hour updated
77
77
  # @example returns
78
78
  # { 0: { hour: '1400', stats: { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
79
79
  # 1: { hour: '1500', stats: { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
@@ -88,39 +88,39 @@ module QaServer
88
88
  averages
89
89
  end
90
90
 
91
- private
91
+ private
92
92
 
93
- def records_by(authority_name, action, time_period)
94
- where_clause = { dt_stamp: time_period }
95
- where_clause[:authority] = authority_name unless authority_name.nil? || authority_name == ALL_AUTH
96
- where_clause[:action] = action unless action.nil? || action == ALL_ACTIONS
97
- performance_data_class.where(where_clause)
98
- end
93
+ def records_by(authority_name, action, time_period)
94
+ where_clause = { dt_stamp: time_period }
95
+ where_clause[:authority] = authority_name unless authority_name.nil? || authority_name == ALL_AUTH
96
+ where_clause[:action] = action unless action.nil? || action == ALL_ACTIONS
97
+ performance_data_class.where(where_clause)
98
+ end
99
99
 
100
- def performance_by_hour_label(idx, start_hour)
101
- if idx == 23
102
- I18n.t('qa_server.monitor_status.performance.now')
103
- elsif ((idx + 1) % 2).zero?
104
- (start_hour.hour * 100).to_s
105
- else
106
- ""
107
- end
100
+ def performance_by_hour_label(idx, start_hour)
101
+ if idx == 23
102
+ I18n.t('qa_server.monitor_status.performance.now')
103
+ elsif ((idx + 1) % 2).zero?
104
+ (start_hour.hour * 100).to_s
105
+ else
106
+ " "
108
107
  end
108
+ end
109
109
 
110
- def performance_by_day_label(idx, start_day)
111
- if idx == 29
112
- I18n.t('qa_server.monitor_status.performance.today')
113
- elsif ((idx + 1) % 5).zero?
114
- start_day.strftime("%m-%d")
115
- else
116
- ""
117
- end
110
+ def performance_by_day_label(idx, start_day)
111
+ if idx == 29
112
+ I18n.t('qa_server.monitor_status.performance.today')
113
+ elsif ((idx + 1) % 5).zero?
114
+ start_day.strftime("%m-%d")
115
+ else
116
+ " "
118
117
  end
118
+ end
119
119
 
120
- def calculate_from_records(records, range_idx, range_label)
121
- stats = stats_calculator_class.new(records).calculate_average_stats
122
- { STATS => stats, range_idx => range_label }
123
- end
120
+ def calculate_from_records(records, range_idx, range_label)
121
+ stats = stats_calculator_class.new(records).calculate_average_stats
122
+ { STATS => stats, range_idx => range_label }
123
+ end
124
124
  end
125
125
  end
126
126
  end
@@ -31,7 +31,7 @@ module QaServer
31
31
  # @param action [Symbol] action performed by the request (e.g. :search, :fetch, :all_actions)
32
32
  # @param data [Hash] data to use to generate the graph
33
33
  # @see QaServer::PerformanceGraphDataService.calculate_last_12_months
34
- def generate_monthly_graph(authority_name: ALL_AUTH, action:, data:)
34
+ def generate_year_graph(authority_name: ALL_AUTH, action:, data:)
35
35
  gruff_data = rework_performance_data_for_gruff(data, BY_MONTH)
36
36
  create_gruff_graph(gruff_data,
37
37
  performance_graph_full_path(authority_name, action, FOR_YEAR),
@@ -44,7 +44,7 @@ module QaServer
44
44
  # @param action [Symbol] action performed by the request (e.g. :search, :fetch, :all_actions)
45
45
  # @param data [Hash] data to use to generate the graph
46
46
  # @see QaServer::PerformanceGraphDataService.calculate_last_30_days
47
- def generate_daily_graph(authority_name: ALL_AUTH, action:, data:)
47
+ def generate_month_graph(authority_name: ALL_AUTH, action:, data:)
48
48
  gruff_data = rework_performance_data_for_gruff(data, BY_DAY)
49
49
  create_gruff_graph(gruff_data,
50
50
  performance_graph_full_path(authority_name, action, FOR_MONTH),
@@ -56,76 +56,76 @@ module QaServer
56
56
  # @param action [Symbol] action performed by the request (e.g. :search, :fetch, :all_actions)
57
57
  # @param data [Hash] data to use to generate the graph
58
58
  # @see QaServer::PerformanceGraphDataService.calculate_last_24_hours
59
- def generate_hourly_graph(authority_name: ALL_AUTH, action:, data:)
59
+ def generate_day_graph(authority_name: ALL_AUTH, action:, data:)
60
60
  gruff_data = rework_performance_data_for_gruff(data, BY_HOUR)
61
61
  create_gruff_graph(gruff_data,
62
62
  performance_graph_full_path(authority_name, action, FOR_DAY),
63
63
  I18n.t('qa_server.monitor_status.performance.x_axis_hour'))
64
64
  end
65
65
 
66
- private
66
+ private
67
67
 
68
- def performance_graph_full_path(authority_name, action, time_period)
69
- graph_full_path(graph_filename(authority_name, action, time_period))
70
- end
68
+ def performance_graph_full_path(authority_name, action, time_period)
69
+ graph_full_path(graph_filename(authority_name, action, time_period))
70
+ end
71
71
 
72
- def graph_filename(authority_name, action, time_period)
73
- "performance_of_#{authority_name}_#{action}_for_#{time_period}_graph.png"
74
- end
72
+ def graph_filename(authority_name, action, time_period)
73
+ "performance_of_#{authority_name}_#{action}_for_#{time_period}_graph.png"
74
+ end
75
75
 
76
- def rework_performance_data_for_gruff(performance_data, label_key)
77
- labels = {}
78
- # full_load_data = []
79
- retrieve_data = []
80
- graph_load_data = []
81
- normalization_data = []
82
- performance_data.each do |i, data|
83
- labels[i] = data[label_key]
84
- retrieve_data << data[STATS][AVG_RETR]
85
- graph_load_data << graph_load_time(data)
86
- normalization_data << data[STATS][AVG_NORM]
87
- end
88
- [labels, retrieve_data, graph_load_data, normalization_data]
76
+ def rework_performance_data_for_gruff(performance_data, label_key)
77
+ labels = {}
78
+ # full_load_data = []
79
+ retrieve_data = []
80
+ graph_load_data = []
81
+ normalization_data = []
82
+ performance_data.each do |i, data|
83
+ labels[i] = data[label_key]
84
+ retrieve_data << data[STATS][AVG_RETR]
85
+ graph_load_data << graph_load_time(data)
86
+ normalization_data << data[STATS][AVG_NORM]
89
87
  end
88
+ [labels, retrieve_data, graph_load_data, normalization_data]
89
+ end
90
90
 
91
- def graph_load_time(data)
92
- # For some sense of backward compatibility and to avoid losing the usefulness of previously collected data,
93
- # create the graph using the old :load stat when both :retrieve and :graph_load are 0. If the value truly
94
- # is 0, then :load will also be 0.
95
- # NOTE: It's ok to use AVG_RETR for the retrieve data point because it is 0.
96
- # rubocop:disable Style/TernaryParentheses
97
- (data[STATS][AVG_RETR].zero? && data[STATS][AVG_GRPH].zero?) ? data[STATS][AVG_LOAD] : data[STATS][AVG_GRPH]
98
- # rubocop:enable Style/TernaryParentheses
99
- end
91
+ def graph_load_time(data)
92
+ # For some sense of backward compatibility and to avoid losing the usefulness of previously collected data,
93
+ # create the graph using the old :load stat when both :retrieve and :graph_load are 0. If the value truly
94
+ # is 0, then :load will also be 0.
95
+ # NOTE: It's ok to use AVG_RETR for the retrieve data point because it is 0.
96
+ # rubocop:disable Style/TernaryParentheses
97
+ (data[STATS][AVG_RETR].zero? && data[STATS][AVG_GRPH].zero?) ? data[STATS][AVG_LOAD] : data[STATS][AVG_GRPH]
98
+ # rubocop:enable Style/TernaryParentheses
99
+ end
100
100
 
101
- def performance_graph_theme(g, x_axis_label)
102
- g.theme_pastel
103
- g.colors = [QaServer.config.performance_normalization_color,
104
- QaServer.config.performance_graph_load_color,
105
- QaServer.config.performance_retrieve_color]
106
- g.marker_font_size = 12
107
- g.x_axis_increment = 10
108
- g.x_axis_label = x_axis_label
109
- g.y_axis_label = I18n.t('qa_server.monitor_status.performance.y_axis_ms')
110
- g.minimum_value = 0
111
- g.maximum_value = QaServer.config.performance_y_axis_max
112
- end
101
+ def performance_graph_theme(g, x_axis_label)
102
+ g.theme_pastel
103
+ g.colors = [QaServer.config.performance_normalization_color,
104
+ QaServer.config.performance_graph_load_color,
105
+ QaServer.config.performance_retrieve_color]
106
+ g.marker_font_size = 12
107
+ g.x_axis_increment = 10
108
+ g.x_axis_label = x_axis_label
109
+ g.y_axis_label = I18n.t('qa_server.monitor_status.performance.y_axis_ms')
110
+ g.minimum_value = 0
111
+ g.maximum_value = QaServer.config.performance_y_axis_max
112
+ end
113
113
 
114
- def create_gruff_graph(performance_data, performance_graph_full_path, x_axis_label)
115
- g = Gruff::StackedBar.new
116
- performance_graph_theme(g, x_axis_label)
117
- g.labels = performance_data[0]
118
- g.data(I18n.t('qa_server.monitor_status.performance.retrieve_time_ms'), performance_data[1])
119
- g.data(I18n.t('qa_server.monitor_status.performance.graph_load_time_ms'), performance_data[2])
120
- g.data(I18n.t('qa_server.monitor_status.performance.normalization_time_ms'), performance_data[3])
121
- g.write performance_graph_full_path
122
- end
114
+ def create_gruff_graph(performance_data, performance_graph_full_path, x_axis_label)
115
+ g = Gruff::StackedBar.new
116
+ performance_graph_theme(g, x_axis_label)
117
+ g.labels = performance_data[0]
118
+ g.data(I18n.t('qa_server.monitor_status.performance.retrieve_time_ms'), performance_data[1])
119
+ g.data(I18n.t('qa_server.monitor_status.performance.graph_load_time_ms'), performance_data[2])
120
+ g.data(I18n.t('qa_server.monitor_status.performance.normalization_time_ms'), performance_data[3])
121
+ g.write performance_graph_full_path
122
+ end
123
123
 
124
- def log_failure(authority_name, action, time_period)
125
- relative_path = performance_graph_image_path(authority_name: authority_name, action: action, time_period: time_period)
126
- exists = performance_graph_image_exists?(authority_name: authority_name, action: action, time_period: time_period)
127
- QaServer.config.monitor_logger.warn("FAILED to write performance graph at #{relative_path}") unless exists
128
- end
124
+ def log_failure(authority_name, action, time_period)
125
+ relative_path = performance_graph_image_path(authority_name: authority_name, action: action, time_period: time_period)
126
+ exists = performance_graph_image_exists?(authority_name: authority_name, action: action, time_period: time_period)
127
+ QaServer.config.monitor_logger.warn("FAILED to write performance graph at #{relative_path}") unless exists
128
+ end
129
129
  end
130
130
  end
131
131
  end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+ # This class calculates min, max, average stats for load, normalization, and full request times for a given set of performance records.
3
+ require 'matrix'
4
+ module QaServer
5
+ class PerformancePerByteCalculatorService
6
+ include QaServer::PerformanceHistoryDataKeys
7
+
8
+ TIME = 0
9
+ BYTES = 1
10
+
11
+ attr_reader :n, :stats, :records
12
+
13
+ # @param records [Array <Qa::PerformanceHistory>] set of records used to calculate the statistics
14
+ def initialize(records:, n:)
15
+ @records = records
16
+ @n = n
17
+ @stats = {}
18
+ end
19
+
20
+ # Calculate performance statistics with percentiles. Min is at the 10th percentile. Max is at the 90th percentile.
21
+ # @return [Hash] hash of the statistics
22
+ # @example
23
+ # { data_raw_bytes_from_source: [16271, 16271],
24
+ # retrieve_bytes_per_ms: [67.24433786890475, 55.51210410757532],
25
+ # retrieve_ms_per_byte: [0.014871140555351083, 0.018014089288745542]
26
+ # graph_load_bytes_per_ms_ms: [86.74089418722461, 54.97464153778724],
27
+ # graph_load_ms_per_byte: [0.011528587632974647, 0.018190205011389522],
28
+ # normalization_bytes_per_ms: [64.70169466560836, 89.25337465693322],
29
+ # normalization_ms_per_byte: [0.01530700843338457, 0.015455545718983178]
30
+ # }
31
+ def calculate
32
+ extract_bytes
33
+ calculate_retrieve_stats
34
+ calculate_graph_load_stats
35
+ calculate_normalization_stats
36
+ stats
37
+ end
38
+
39
+ private
40
+
41
+ def extract_bytes
42
+ stats[SRC_BYTES] = retrieve_data.count.zero? ? 0 : retrieve_data.map { |d| d[BYTES] }
43
+ end
44
+
45
+ def calculate_retrieve_stats
46
+ stats[BPMS_RETR] = calculate_bytes_per_ms(retrieve_data)
47
+ stats[MSPB_RETR] = calculate_ms_per_byte(retrieve_data)
48
+ end
49
+
50
+ def calculate_graph_load_stats
51
+ stats[BPMS_GRPH] = calculate_bytes_per_ms(graph_load_data)
52
+ stats[MSPB_GRPH] = calculate_ms_per_byte(graph_load_data)
53
+ end
54
+
55
+ def calculate_normalization_stats
56
+ stats[BPMS_NORM] = calculate_bytes_per_ms(norm_data)
57
+ stats[MSPB_NORM] = calculate_ms_per_byte(norm_data)
58
+ end
59
+
60
+ def calculate_bytes_per_ms(data)
61
+ return 0 if data.count.zero?
62
+ return data[0][BYTES] / d[0][TIME] if data.count == 1
63
+ data.map { |d| d[BYTES] / d[TIME] }
64
+ end
65
+
66
+ def calculate_ms_per_byte(data)
67
+ return 0 if data.count.zero?
68
+ return data[0][TIME] / d[0][BYTES] if data.count == 1
69
+ data.map { |d| d[TIME] / d[BYTES] }
70
+ end
71
+
72
+ def data(column)
73
+ records.where.not(column => nil).order(dt_stamp: :desc).limit(n).pluck(column, :size_bytes)
74
+ end
75
+
76
+ def retrieve_data
77
+ @retrieve_data ||= data(:retrieve_time_ms)
78
+ end
79
+
80
+ def graph_load_data
81
+ @graph_data ||= data(:graph_load_time_ms)
82
+ end
83
+
84
+ def norm_data
85
+ @norm_data ||= data(:normalization_time_ms)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ # This class calculates performance stats based on size of data.
3
+ module QaServer
4
+ class PerformancePerByteDataService
5
+ class << self
6
+ include QaServer::PerformanceHistoryDataKeys
7
+
8
+ class_attribute :stats_calculator_class, :performance_data_class
9
+ self.stats_calculator_class = QaServer::PerformancePerByteCalculatorService
10
+ self.performance_data_class = QaServer::PerformanceHistory
11
+
12
+ # Performance data based on size of data.
13
+ # @param authority_name [String] name of an authority
14
+ # @param action [Symbol] :search, :fetch, or :all_actions
15
+ # @param n [Integer] calculate stats for last n records
16
+ # @returns [Hash] performance statistics based on size of data
17
+ # @example returns for n=2
18
+ # { data_raw_bytes_from_source: [16271, 16271],
19
+ # retrieve_bytes_per_ms: [67.24433786890475, 55.51210410757532],
20
+ # retrieve_ms_per_byte: [0.014871140555351083, 0.018014089288745542]
21
+ # graph_load_bytes_per_ms_ms: [86.74089418722461, 54.97464153778724],
22
+ # graph_load_ms_per_byte: [0.011528587632974647, 0.018190205011389522],
23
+ # normalization_bytes_per_ms: [64.70169466560836, 89.25337465693322],
24
+ # normalization_ms_per_byte: [0.01530700843338457, 0.015455545718983178]
25
+ # }
26
+ def calculate(authority_name:, action:, n: 10)
27
+ records = records_by(authority_name, action)
28
+ stats_calculator_class.new(records: records, n: n).calculate
29
+ end
30
+
31
+ private
32
+
33
+ def records_by(authority_name, action)
34
+ where_clause = {}
35
+ where_clause[:authority] = authority_name unless authority_name.nil? || authority_name == ALL_AUTH
36
+ where_clause[:action] = action unless action.nil? || action == ALL_ACTIONS
37
+ performance_data_class.where(where_clause)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -32,7 +32,7 @@ module QaServer
32
32
 
33
33
  def self.load_config(authority_name, status_log)
34
34
  scenarios_config = YAML.load_file(scenario_path(authority_name))
35
- unless scenarios_config.present?
35
+ if scenarios_config.blank?
36
36
  status_log.add(authority_name: authority_name,
37
37
  status: QaServer::ScenarioValidator::FAIL,
38
38
  error_message: "Unable to load scenarios for authority '#{authority_name}'; cause: UNKNOWN")
@@ -63,31 +63,31 @@ module QaServer
63
63
  where_with_authority(where_clause, auth_name, auth_table)
64
64
  end
65
65
 
66
- private
66
+ private
67
67
 
68
- def where_for_dt_stamp(dt_table, dt_column, time_period)
69
- end_range = QaServer::TimeService.current_time
70
- start_range = end_range - time_period
71
- where_clause = { dt_column => start_range..end_range }
72
- where_clause = { dt_table => where_clause } unless dt_table.nil?
73
- where_clause
74
- end
68
+ def where_for_dt_stamp(dt_table, dt_column, time_period)
69
+ end_range = QaServer::TimeService.current_time
70
+ start_range = end_range - time_period
71
+ where_clause = { dt_column => start_range..end_range }
72
+ where_clause = { dt_table => where_clause } unless dt_table.nil?
73
+ where_clause
74
+ end
75
75
 
76
- def where_with_authority(where_clause, auth_name, auth_table)
77
- return where_clause if auth_name.nil?
78
- if auth_table.nil?
79
- where_clause[:authority] = auth_name
80
- else
81
- where_clause[auth_table] = { authority: auth_name }
82
- end
83
- where_clause
76
+ def where_with_authority(where_clause, auth_name, auth_table)
77
+ return where_clause if auth_name.nil?
78
+ if auth_table.nil?
79
+ where_clause[:authority] = auth_name
80
+ else
81
+ where_clause[auth_table] = { authority: auth_name }
84
82
  end
83
+ where_clause
84
+ end
85
85
 
86
- def validate_params(auth_name, auth_table, dt_table)
87
- raise ArgumentError, "Do not specify auth_table when auth_name is not specified" if auth_table.present? && auth_name.nil?
88
- return if auth_name.nil?
89
- raise ArgumentError, "Either both table names need to be specified or neither" if auth_table.present? ^ dt_table.present?
90
- end
86
+ def validate_params(auth_name, auth_table, dt_table)
87
+ raise ArgumentError, "Do not specify auth_table when auth_name is not specified" if auth_table.present? && auth_name.nil?
88
+ return if auth_name.nil?
89
+ raise ArgumentError, "Either both table names need to be specified or neither" if auth_table.present? ^ dt_table.present?
90
+ end
91
91
  end
92
92
  end
93
93
  end
@@ -8,6 +8,7 @@ module QaServer
8
8
 
9
9
  VALIDATE_CONNECTION = :connection
10
10
  VALIDATE_ACCURACY = :accuracy
11
+ VALIDATE_ACCURACY_COMPARISON = :accuracy_comparison
11
12
  ALL_VALIDATIONS = :all_validations
12
13
  DEFAULT_VALIDATION_TYPE = VALIDATE_CONNECTION
13
14
 
@@ -33,92 +34,103 @@ module QaServer
33
34
  log
34
35
  end
35
36
 
36
- private
37
-
38
- # Log the structure of the scenario and status of a test run.
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)
49
- end
50
-
51
- def run_accuracy_scenario
52
- # ABSTRACT - must be implemented by scenario validator for specific types
53
- end
54
-
55
- def run_connection_scenario
56
- # ABSTRACT - must be implemented by scenario validator for specific types
57
- end
58
-
59
- # Runs the test in the block passed by the specific scenario type.
60
- # @return [Symbol] :good (PASS) or :unknown (UNKNOWN) based on whether enough results were returned
61
- def test_connection(min_expected_size: MIN_EXPECTED_SIZE, scenario_type_name:)
62
- dt_start = QaServer::TimeService.current_time
63
- results = yield if block_given?
64
- dt_end = QaServer::TimeService.current_time
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, error_message: errmsg, normalization_run_time: (dt_end - dt_start)) # TODO: need to get run times from results
69
- rescue Exception => e
70
- dt_end = QaServer::TimeService.current_time
71
- log(status: FAIL, error_message: "Exception executing #{scenario_type_name} scenario; cause: #{e.message}", request_run_time: (dt_end - dt_start))
72
- end
73
-
74
- def authority
75
- scenario.authority
76
- end
77
-
78
- def authority_name
79
- scenario.authority_name.upcase
80
- end
81
-
82
- def subauthority_name
83
- scenario.subauthority_name
84
- end
85
-
86
- def service
87
- scenario.service
88
- end
89
-
90
- def url
91
- scenario.url
92
- end
93
-
94
- def action
95
- # ABSTRACT - must be implemented by scenario validator for specific types
96
- end
97
-
98
- def scenario_validation_type
99
- return VALIDATE_CONNECTION if connection_scenario?
100
- return VALIDATE_ACCURACY if accuracy_scenario?
101
- nil
102
- end
103
-
104
- def validating_connections?
105
- return true if validation_type == VALIDATE_CONNECTION || validation_type == ALL_VALIDATIONS
106
- false
107
- end
108
-
109
- def validating_accuracy?
110
- return true if validation_type == VALIDATE_ACCURACY || validation_type == ALL_VALIDATIONS
111
- false
112
- end
113
-
114
- def accuracy_scenario?
115
- # ABSTRACT define in specific scenario type validator (i.e. QaServer::TermScenarioValidator, QaServer::SearchScenarioValidator)
116
- false
117
- end
118
-
119
- def connection_scenario?
120
- # ABSTRACT define in specific scenario type validator (i.e. QaServer::TermScenarioValidator, QaServer::SearchScenarioValidator)
121
- false
122
- end
37
+ private
38
+
39
+ # Log the structure of the scenario and status of a test run.
40
+ # @param [Hash] status_info holding information to be logged
41
+ # @see QaServer::ScenarioLogger
42
+ def log(status_info = {})
43
+ status_info[:authority_name] = authority_name
44
+ status_info[:validation_type] = scenario_validation_type
45
+ status_info[:subauth] = subauthority_name
46
+ status_info[:service] = service
47
+ status_info[:action] = action
48
+ status_info[:url] = url
49
+ status_info[:request_data] = request_data
50
+ status_log.add(status_info)
51
+ end
52
+
53
+ def run_accuracy_scenario
54
+ # ABSTRACT - must be implemented by scenario validator for specific types
55
+ end
56
+
57
+ def run_connection_scenario
58
+ # ABSTRACT - must be implemented by scenario validator for specific types
59
+ end
60
+
61
+ def request_data
62
+ # ABSTRACT - must be implemented by scenario validator for specific types
63
+ end
64
+
65
+ # Runs the test in the block passed by the specific scenario type.
66
+ # @return [Symbol] :good (PASS) or :unknown (UNKNOWN) based on whether enough results were returned
67
+ def test_connection(min_expected_size: MIN_EXPECTED_SIZE, scenario_type_name:)
68
+ dt_start = QaServer::TimeService.current_time
69
+ results = yield if block_given?
70
+ dt_end = QaServer::TimeService.current_time
71
+ actual_size = results.to_s.length
72
+ status = actual_size > min_expected_size ? PASS : UNKNOWN
73
+ errmsg = status == PASS ? '' : "#{scenario_type_name.capitalize} scenario unknown status; cause: Results actual size (#{actual_size} < expected size (#{min_expected_size})"
74
+ log(status: status, error_message: errmsg, normalization_run_time: (dt_end - dt_start)) # TODO: need to get run times from results
75
+ rescue Exception => e
76
+ dt_end = QaServer::TimeService.current_time
77
+ log(status: FAIL, error_message: "Exception executing #{scenario_type_name} scenario; cause: #{e.message}", request_run_time: (dt_end - dt_start))
78
+ end
79
+
80
+ # @return [Qa::Authorities::LinkedData::GenericAuthority] authority instance the scenarios run against
81
+ def authority
82
+ scenario.authority
83
+ end
84
+
85
+ # @return [Symbol] name of the authority (e.g. :CERL_LD4L_CACHE)
86
+ def authority_name
87
+ scenario.authority_name.upcase
88
+ end
89
+
90
+ # @return [String] name of the subauthority (e.g. "person")
91
+ def subauthority_name
92
+ scenario.subauthority_name
93
+ end
94
+
95
+ # @return [String] service providing the data (e.g. "ld4l_cache" or "direct")
96
+ def service
97
+ scenario.service
98
+ end
99
+
100
+ # @return [String] relative URL with ready to execute (e.g. ""/authorities/search/linked_data/cerl_ld4l_cache/person?q=office")
101
+ def url
102
+ scenario.url
103
+ end
104
+
105
+ # @return [String] action being tested (e.g. "search" or "term")
106
+ def action
107
+ # ABSTRACT - must be implemented by scenario validator for specific types
108
+ end
109
+
110
+ def scenario_validation_type
111
+ return VALIDATE_CONNECTION if connection_scenario?
112
+ return VALIDATE_ACCURACY if accuracy_scenario?
113
+ nil
114
+ end
115
+
116
+ def validating_connections?
117
+ return true if validation_type == VALIDATE_CONNECTION || validation_type == ALL_VALIDATIONS
118
+ false
119
+ end
120
+
121
+ def validating_accuracy?
122
+ return true if [VALIDATE_ACCURACY, VALIDATE_ACCURACY_COMPARISON, ALL_VALIDATIONS].include? validation_type
123
+ false
124
+ end
125
+
126
+ def accuracy_scenario?
127
+ # ABSTRACT define in specific scenario type validator (i.e. QaServer::TermScenarioValidator, QaServer::SearchScenarioValidator)
128
+ false
129
+ end
130
+
131
+ def connection_scenario?
132
+ # ABSTRACT define in specific scenario type validator (i.e. QaServer::TermScenarioValidator, QaServer::SearchScenarioValidator)
133
+ false
134
+ end
123
135
  end
124
136
  end