qa_server 7.2.0 → 7.5.1

Sign up to get free protection for your applications and to get access to all the features.
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