qa_server 5.4.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -0
- data/CHANGELOG.md +4 -0
- data/app/controllers/qa_server/monitor_status_controller.rb +25 -42
- data/app/models/qa_server/performance_cache.rb +1 -0
- data/app/models/qa_server/performance_history.rb +22 -17
- data/app/models/qa_server/scenario_run_history.rb +56 -36
- data/app/models/qa_server/scenario_run_registry.rb +14 -8
- data/app/models/qa_server/scenario_run_summary.rb +1 -1
- data/app/prepends/prepended_rdf/rdf_graph.rb +4 -4
- data/app/presenters/qa_server/monitor_status/current_status_presenter.rb +1 -1
- data/app/services/qa_server/performance_graph_data_service.rb +70 -36
- data/lib/generators/qa_server/templates/config/initializers/qa_server.rb +5 -0
- data/lib/qa_server/configuration.rb +9 -0
- data/lib/qa_server/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cfe60b29f718a16c9c86b62e0bd7807c746147b1
|
|
4
|
+
data.tar.gz: 51dc3758debb4b924b7859ca82f9ed49eb3475a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56e1811a7ee5b562a3e24d77fecba594955b5410824863a0745f895b2541d5d735e21c33b29b33047c4cb1d257489dc498d9bdb774f097a74c64954c2c7e0da8
|
|
7
|
+
data.tar.gz: '084ba6a28a84a2a235c2cb69f2aed5285399ba2e3718135302a5dbf3c297a225407a348cbf6b87ef1705b5cc59016b1bd3ae49a7b0947dda28c215961f9e0f9a'
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -13,9 +13,7 @@ module QaServer
|
|
|
13
13
|
|
|
14
14
|
# Sets up presenter with data to display in the UI
|
|
15
15
|
def index
|
|
16
|
-
|
|
17
|
-
historical_data = refresh_history
|
|
18
|
-
performance_data = refresh_performance
|
|
16
|
+
latest_run
|
|
19
17
|
@presenter = presenter_class.new(current_summary: latest_summary,
|
|
20
18
|
current_failure_data: latest_failures,
|
|
21
19
|
historical_summary_data: historical_data,
|
|
@@ -25,49 +23,39 @@ module QaServer
|
|
|
25
23
|
|
|
26
24
|
private
|
|
27
25
|
|
|
26
|
+
# Sets @latest_run [QaServer::ScenarioRunRegistry]
|
|
28
27
|
def latest_run
|
|
29
|
-
|
|
28
|
+
Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: refresh_tests?) do
|
|
29
|
+
Rails.logger.info("#{self.class}##{__method__} - Running Tests - cache expired or refresh requested (#{refresh_tests?})")
|
|
30
|
+
validate(authorities_list)
|
|
31
|
+
scenario_run_registry_class.save_run(scenarios_results: status_log.to_a)
|
|
32
|
+
scenario_run_registry_class.latest_run
|
|
33
|
+
end
|
|
30
34
|
end
|
|
31
35
|
|
|
36
|
+
# Sets @latest_summary [QaServer::ScenarioRunSummary]
|
|
32
37
|
def latest_summary
|
|
33
|
-
|
|
38
|
+
scenario_history_class.run_summary(scenario_run: latest_run, force: refresh_tests?)
|
|
34
39
|
end
|
|
35
40
|
|
|
36
41
|
def latest_failures
|
|
37
|
-
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def update_summary_and_data
|
|
41
|
-
scenario_run_registry_class.save_run(scenarios_results: status_log.to_a)
|
|
42
|
-
@latest_summary = nil # reset so next request recalculates
|
|
43
|
-
@latest_failures = nil # reset so next request recalculates
|
|
42
|
+
scenario_history_class.run_failures(run_id: latest_run.id, force: refresh_tests?)
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def historical_summary_data(refresh: false)
|
|
51
|
-
# TODO: Make this refresh the same way performance data refreshes.
|
|
52
|
-
# Requires historical graph to move out of presenter so it can be created here only with refresh.
|
|
53
|
-
if refresh
|
|
54
|
-
@historical_summary_data = scenario_history_class.historical_summary
|
|
55
|
-
# TODO: Need to recreate graph here. And need to only read the graph in presenter.
|
|
56
|
-
end
|
|
57
|
-
@historical_summary_data ||= scenario_history_class.historical_summary
|
|
45
|
+
# Sets @historical_data [Array<Hash>]
|
|
46
|
+
def historical_data
|
|
47
|
+
scenario_history_class.historical_summary(force: refresh_history?)
|
|
58
48
|
end
|
|
59
49
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
@performance_data = nil if refresh
|
|
64
|
-
@performance_data ||= performance_history_class.performance_data(datatype: datatype)
|
|
50
|
+
# Sets @performance_data [Hash<Hash>]
|
|
51
|
+
def performance_data
|
|
52
|
+
performance_history_class.performance_data(datatype: performance_datatype, force: refresh_performance?)
|
|
65
53
|
end
|
|
66
54
|
|
|
67
|
-
def performance_datatype
|
|
68
|
-
return :all if display_performance_datatable? && display_performance_graph?
|
|
55
|
+
def performance_datatype
|
|
56
|
+
return :all if display_performance_datatable? && display_performance_graph?
|
|
69
57
|
return :datatable if display_performance_datatable?
|
|
70
|
-
return :graph if display_performance_graph?
|
|
58
|
+
return :graph if display_performance_graph?
|
|
71
59
|
:none
|
|
72
60
|
end
|
|
73
61
|
|
|
@@ -79,12 +67,6 @@ module QaServer
|
|
|
79
67
|
@display_performance_graph ||= QaServer.config.display_performance_graph?
|
|
80
68
|
end
|
|
81
69
|
|
|
82
|
-
def refresh_tests
|
|
83
|
-
return unless refresh_tests?
|
|
84
|
-
validate(authorities_list)
|
|
85
|
-
update_summary_and_data
|
|
86
|
-
end
|
|
87
|
-
|
|
88
70
|
def refresh_history
|
|
89
71
|
historical_summary_data(refresh: refresh_history?)
|
|
90
72
|
end
|
|
@@ -98,12 +80,13 @@ module QaServer
|
|
|
98
80
|
end
|
|
99
81
|
|
|
100
82
|
def refresh_all?
|
|
83
|
+
return false unless refresh?
|
|
101
84
|
params[:refresh].nil? || params[:refresh].casecmp?('all') # nil is for backward compatibility
|
|
102
85
|
end
|
|
103
86
|
|
|
104
87
|
def refresh_tests?
|
|
105
|
-
return false unless refresh?
|
|
106
|
-
refresh_all? || params[:refresh].casecmp?('tests')
|
|
88
|
+
return false unless refresh?
|
|
89
|
+
refresh_all? || params[:refresh].casecmp?('tests')
|
|
107
90
|
end
|
|
108
91
|
|
|
109
92
|
def refresh_history?
|
|
@@ -112,8 +95,8 @@ module QaServer
|
|
|
112
95
|
end
|
|
113
96
|
|
|
114
97
|
def refresh_performance?
|
|
115
|
-
return false unless refresh?
|
|
116
|
-
refresh_all? || params[:refresh].casecmp?('performance')
|
|
98
|
+
return false unless refresh?
|
|
99
|
+
refresh_all? || params[:refresh].casecmp?('performance')
|
|
117
100
|
end
|
|
118
101
|
end
|
|
119
102
|
end
|
|
@@ -64,10 +64,10 @@ module QaServer
|
|
|
64
64
|
# },
|
|
65
65
|
# AGROVOC_LD4L_CACHE: { ... # same data for each authority }
|
|
66
66
|
# }
|
|
67
|
-
def performance_data(datatype: :datatable)
|
|
67
|
+
def performance_data(datatype: :datatable, force: false)
|
|
68
68
|
return if datatype == :none
|
|
69
69
|
QaServer.config.performance_cache.write_all
|
|
70
|
-
data = calculate_data(datatype)
|
|
70
|
+
data = calculate_data(datatype, force: force)
|
|
71
71
|
graphing_service_class.create_performance_graphs(performance_data: data) if calculate_graphdata? datatype
|
|
72
72
|
data
|
|
73
73
|
end
|
|
@@ -82,23 +82,23 @@ module QaServer
|
|
|
82
82
|
datatype == :graph || datatype == :all
|
|
83
83
|
end
|
|
84
84
|
|
|
85
|
-
def calculate_data(datatype)
|
|
85
|
+
def calculate_data(datatype, force:)
|
|
86
86
|
data = {}
|
|
87
87
|
auths = authority_list_class.authorities_list
|
|
88
|
-
data[ALL_AUTH] = data_for_authority(datatype: datatype)
|
|
89
|
-
auths.each { |auth_name| data[auth_name] = data_for_authority(authority_name: auth_name, datatype: datatype) }
|
|
88
|
+
data[ALL_AUTH] = data_for_authority(datatype: datatype, force: force)
|
|
89
|
+
auths.each { |auth_name| data[auth_name] = data_for_authority(authority_name: auth_name, datatype: datatype, force: force) }
|
|
90
90
|
data
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
def data_for_authority(authority_name: nil, datatype:)
|
|
93
|
+
def data_for_authority(authority_name: nil, datatype:, force:)
|
|
94
94
|
action_data = {}
|
|
95
95
|
[:search, :fetch, :all_actions].each do |action|
|
|
96
96
|
data = {}
|
|
97
|
-
data[FOR_DATATABLE] = data_table_stats(authority_name, action) if calculate_datatable?(datatype)
|
|
97
|
+
data[FOR_DATATABLE] = data_table_stats(authority_name, action, force: force) if calculate_datatable?(datatype)
|
|
98
98
|
if calculate_graphdata?(datatype)
|
|
99
|
-
data[FOR_DAY] = graph_data_service_class.average_last_24_hours(authority_name: authority_name, action: action)
|
|
100
|
-
data[FOR_MONTH] = graph_data_service_class.average_last_30_days(authority_name: authority_name, action: action)
|
|
101
|
-
data[FOR_YEAR] = graph_data_service_class.average_last_12_months(authority_name: authority_name, action: action)
|
|
99
|
+
data[FOR_DAY] = graph_data_service_class.average_last_24_hours(authority_name: authority_name, action: action, force: force)
|
|
100
|
+
data[FOR_MONTH] = graph_data_service_class.average_last_30_days(authority_name: authority_name, action: action, force: force)
|
|
101
|
+
data[FOR_YEAR] = graph_data_service_class.average_last_12_months(authority_name: authority_name, action: action, force: force)
|
|
102
102
|
end
|
|
103
103
|
action_data[action] = data
|
|
104
104
|
end
|
|
@@ -106,18 +106,23 @@ module QaServer
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
# Get statistics for all available data.
|
|
109
|
-
# @param [String]
|
|
109
|
+
# @param auth_name [String] limit statistics to records for the given authority (default: all authorities)
|
|
110
|
+
# @param action [Symbol] one of :search, :fetch, :all_actions
|
|
111
|
+
# @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
|
|
110
112
|
# @returns [Hash] performance statistics for the datatable during the expected time period
|
|
111
113
|
# @example
|
|
112
114
|
# { retrieve_avg_ms: 12.3, graph_load_avg_ms: 2.1, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5,
|
|
113
115
|
# retrieve_10th_ms: 12.3, graph_load_10th_ms: 12.3, normalization_10th_ms: 4.2, full_request_10th_ms: 16.5,
|
|
114
116
|
# retrieve_90th_ms: 12.3, graph_load_90th_ms: 12.3, normalization_90th_ms: 4.2, full_request_90th_ms: 16.5 }
|
|
115
|
-
def data_table_stats(auth_name, action)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
def data_table_stats(auth_name, action, force:)
|
|
118
|
+
Rails.cache.fetch("#{self.class}/#{__method__}/#{auth_name || ALL_AUTH}/#{action}/#{FOR_DATATABLE}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
|
|
119
|
+
Rails.logger.info("#{self.class}##{__method__} - calculating performance datatable stats - cache expired or refresh requested (#{force})")
|
|
120
|
+
records = records_for_last_24_hours(auth_name) ||
|
|
121
|
+
records_for_last_30_days(auth_name) ||
|
|
122
|
+
records_for_last_12_months(auth_name) ||
|
|
123
|
+
all_records(auth_name)
|
|
124
|
+
stats_calculator_class.new(records, action: action).calculate_stats(avg: true, low: true, high: true)
|
|
125
|
+
end
|
|
121
126
|
end
|
|
122
127
|
|
|
123
128
|
def expected_time_period
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
# Provide access to the scenario_results_history database table which tracks specific scenario runs over time.
|
|
3
3
|
module QaServer
|
|
4
|
-
class ScenarioRunHistory < ActiveRecord::Base
|
|
4
|
+
class ScenarioRunHistory < ActiveRecord::Base # rubocop:disable Metrics/ClassLength
|
|
5
5
|
self.table_name = 'scenario_run_history'
|
|
6
6
|
belongs_to :scenario_run_registry
|
|
7
7
|
enum scenario_type: [:connection, :accuracy, :performance], _suffix: :type
|
|
@@ -31,24 +31,28 @@ module QaServer
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# Get a summary of passing/failing tests for a run.
|
|
34
|
-
# @param scenario_run [ScenarioRunRegistry] the run on which to gather statistics
|
|
35
|
-
# @
|
|
36
|
-
# @
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
34
|
+
# @param scenario_run [QaServer::ScenarioRunRegistry] the run on which to gather statistics
|
|
35
|
+
# @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
|
|
36
|
+
# @returns [QaServer::ScenarioRunSummary] statistics on the requested run
|
|
37
|
+
# @example ScenarioRunSummary includes methods for accessing
|
|
38
|
+
# * run_id: 14,
|
|
39
|
+
# * run_dt_stamp:
|
|
40
|
+
# * authority_count: 22,
|
|
41
|
+
# * failing_authority_count: 1
|
|
42
|
+
# * passing_scenario_count: 156,
|
|
43
|
+
# * failing_scenario_count: 3,
|
|
44
|
+
# * total_scenario_count: 159,
|
|
45
|
+
def self.run_summary(scenario_run:, force: false)
|
|
46
|
+
Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
|
|
47
|
+
Rails.logger.info("#{self.class}##{__method__} - creating summary of latest run - cache expired or refresh requested (#{force})")
|
|
48
|
+
status = status_counts_in_run(run_id: scenario_run.id)
|
|
49
|
+
summary_class.new(run_id: scenario_run.id,
|
|
50
|
+
run_dt_stamp: scenario_run.dt_stamp,
|
|
51
|
+
authority_count: authorities_in_run(run_id: scenario_run.id).count,
|
|
52
|
+
failing_authority_count: authorities_with_failures_in_run(run_id: scenario_run.id).count,
|
|
53
|
+
passing_scenario_count: status['good'],
|
|
54
|
+
failing_scenario_count: status['bad'] + status['unknown'])
|
|
55
|
+
end
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
# Get set of all scenario results for a run.
|
|
@@ -85,6 +89,7 @@ module QaServer
|
|
|
85
89
|
# err_message: "Not enough search results returned",
|
|
86
90
|
# scenario_type: :connection
|
|
87
91
|
# run_time: 0.123 } ]
|
|
92
|
+
# @deprecated Not used anywhere. Being removed.
|
|
88
93
|
def self.run_results(run_id:, authority_name: nil, status: nil, url: nil)
|
|
89
94
|
return [] unless run_id
|
|
90
95
|
where = {}
|
|
@@ -94,9 +99,11 @@ module QaServer
|
|
|
94
99
|
where[:url] = url if url.present?
|
|
95
100
|
QaServer::ScenarioRunHistory.where(where).to_a
|
|
96
101
|
end
|
|
102
|
+
deprecation_deprecate run_results: "Not used anywhere. Being removed."
|
|
97
103
|
|
|
98
104
|
# Get set of failures for a run, if any.
|
|
99
105
|
# @param run_id [Integer] the run on which to gather statistics
|
|
106
|
+
# @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
|
|
100
107
|
# @returns [Array<Hash>] scenario details for any failing scenarios in the run
|
|
101
108
|
# @example
|
|
102
109
|
# [ { status: :bad,
|
|
@@ -117,32 +124,43 @@ module QaServer
|
|
|
117
124
|
# err_message: "Not enough search results returned",
|
|
118
125
|
# scenario_type: :connection
|
|
119
126
|
# run_time: 0.123 } ]
|
|
120
|
-
def self.run_failures(run_id:)
|
|
127
|
+
def self.run_failures(run_id:, force: false)
|
|
121
128
|
return [] unless run_id
|
|
122
|
-
|
|
129
|
+
Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
|
|
130
|
+
Rails.logger.info("#{self.class}##{__method__} - finding failures in latest run - cache expired or refresh requested (#{force})")
|
|
131
|
+
QaServer::ScenarioRunHistory.where(scenario_run_registry_id: run_id).where.not(status: :good).to_a
|
|
132
|
+
end
|
|
123
133
|
end
|
|
124
134
|
|
|
125
135
|
# Get a summary level of historical data
|
|
126
|
-
# @returns [Array<
|
|
127
|
-
# @example
|
|
136
|
+
# @returns [Array<Array>] summary of passing/failing tests for each authority
|
|
137
|
+
# @example [auth_name, failing, passing]
|
|
128
138
|
# [ [ 'agrovoc', 0, 24 ],
|
|
129
139
|
# [ 'geonames_ld4l_cache', 2, 22 ] ... ]
|
|
130
|
-
def self.historical_summary
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
data << auth_data
|
|
140
|
+
def self.historical_summary(force: false)
|
|
141
|
+
Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
|
|
142
|
+
Rails.logger.info("#{self.class}##{__method__} - calculating pass/fail per authority across all time - cache expired or refresh requested (#{force})")
|
|
143
|
+
runs = all_runs_per_authority
|
|
144
|
+
failures = failing_runs_per_authority
|
|
145
|
+
return [] unless runs.present?
|
|
146
|
+
data = []
|
|
147
|
+
runs.each do |auth_name, run_count|
|
|
148
|
+
data << pass_fail_stats_for_authority(failures, auth_name, run_count)
|
|
149
|
+
end
|
|
150
|
+
data
|
|
142
151
|
end
|
|
143
|
-
data
|
|
144
152
|
end
|
|
145
153
|
|
|
154
|
+
def self.pass_fail_stats_for_authority(failures, auth_name, run_count)
|
|
155
|
+
auth_data = []
|
|
156
|
+
auth_data[0] = auth_name
|
|
157
|
+
failure_count = failures.key?(auth_name) ? failures[auth_name] : 0
|
|
158
|
+
auth_data[1] = failure_count
|
|
159
|
+
auth_data[2] = run_count - failure_count # passing
|
|
160
|
+
auth_data
|
|
161
|
+
end
|
|
162
|
+
private_class_method :pass_fail_stats_for_authority
|
|
163
|
+
|
|
146
164
|
def self.authorities_in_run(run_id:)
|
|
147
165
|
QaServer::ScenarioRunHistory.where(scenario_run_registry_id: run_id).pluck(:authority_name).uniq
|
|
148
166
|
end
|
|
@@ -153,6 +171,8 @@ module QaServer
|
|
|
153
171
|
end
|
|
154
172
|
private_class_method :authorities_with_failures_in_run
|
|
155
173
|
|
|
174
|
+
# @return [Hash] status counts across all authorities (used for current test summary)
|
|
175
|
+
# @example { "good" => 23, "bad" => 3, "unknown" => 0 }
|
|
156
176
|
def self.status_counts_in_run(run_id:)
|
|
157
177
|
status = QaServer::ScenarioRunHistory.group('status').where(scenario_run_registry_id: run_id).count
|
|
158
178
|
status["good"] = 0 unless status.key? "good"
|
|
@@ -5,7 +5,7 @@ module QaServer
|
|
|
5
5
|
self.table_name = 'scenario_run_registry'
|
|
6
6
|
has_many :scenario_run_history, foreign_key: :scenario_run_registry_id
|
|
7
7
|
|
|
8
|
-
#
|
|
8
|
+
# @return [ScenarioRunRegistry] registry data for latest run (e.g. id, dt_stamp)
|
|
9
9
|
def self.latest_run
|
|
10
10
|
return nil unless QaServer::ScenarioRunRegistry.last
|
|
11
11
|
QaServer::ScenarioRunRegistry.last # Can we count on last to always be the one with the latest dt_stamp?
|
|
@@ -14,21 +14,27 @@ module QaServer
|
|
|
14
14
|
# latest_run.id
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
#
|
|
17
|
+
# @return [Integer] id for latest test run
|
|
18
|
+
# @deprecated Not used anywhere. Being removed.
|
|
18
19
|
def self.latest_run_id
|
|
19
20
|
latest = latest_run
|
|
20
21
|
return nil unless latest
|
|
21
22
|
lastest.id
|
|
22
23
|
end
|
|
24
|
+
deprecation_deprecate latest_run_id: "Not used anywhere. Being removed."
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
# @return [String] datetime stamp of first registered run
|
|
27
|
+
def self.first_run_dt
|
|
28
|
+
Rails.cache.fetch("#{self.class}/#{__method__}", expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour) do
|
|
29
|
+
QaServer::ScenarioRunRegistry.first.dt_stamp.in_time_zone("Eastern Time (US & Canada)").strftime("%m/%d/%y - %I:%M %p")
|
|
30
|
+
end
|
|
27
31
|
end
|
|
28
32
|
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
# Register and save latest test run results
|
|
34
|
+
# @param scenarios_results [Array<Hash>] results of latest test run
|
|
35
|
+
def self.save_run(scenarios_results:)
|
|
36
|
+
run = QaServer::ScenarioRunRegistry.create(dt_stamp: QaServer.current_time)
|
|
37
|
+
scenarios_results.each { |result| QaServer::ScenarioRunHistory.save_result(run_id: run.id, scenario_result: result) }
|
|
31
38
|
end
|
|
32
|
-
private_class_method :dt_stamp_now_et
|
|
33
39
|
end
|
|
34
40
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
#
|
|
2
|
+
# Holds test run summary data providing methods for accessing each data point.
|
|
3
3
|
module QaServer
|
|
4
4
|
class ScenarioRunSummary
|
|
5
5
|
# @return [Integer] the id of the scenario run being summarized
|
|
@@ -17,15 +17,15 @@ module PrependedRdf::RdfGraph
|
|
|
17
17
|
raise TypeError, "#{self} is immutable" if immutable?
|
|
18
18
|
phid, real_url = parse_phid(url)
|
|
19
19
|
performance_udpates = {}
|
|
20
|
-
start_time_s =
|
|
20
|
+
start_time_s = QaServer.current_time_s
|
|
21
21
|
|
|
22
22
|
reader = RDF::Reader.open(real_url, { base_uri: real_url }.merge(options))
|
|
23
23
|
|
|
24
|
-
end_time_s =
|
|
24
|
+
end_time_s = QaServer.current_time_s
|
|
25
25
|
performance_udpates[:retrieve_time_ms] = (end_time_s - start_time_s) * 1000
|
|
26
26
|
QaServer.config.performance_tracker.write "#{format('%.6f', end_time_s - start_time_s)}, " # read data
|
|
27
27
|
|
|
28
|
-
start_time_s =
|
|
28
|
+
start_time_s = QaServer.current_time_s
|
|
29
29
|
|
|
30
30
|
if graph_name
|
|
31
31
|
statements = []
|
|
@@ -40,7 +40,7 @@ module PrependedRdf::RdfGraph
|
|
|
40
40
|
nil
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
end_time_s =
|
|
43
|
+
end_time_s = QaServer.current_time_s
|
|
44
44
|
performance_udpates[:graph_load_time_ms] = (end_time_s - start_time_s) * 1000
|
|
45
45
|
QaServer.config.performance_cache.update(id: phid, updates: performance_udpates)
|
|
46
46
|
QaServer.config.performance_tracker.write "#{format('%.6f', end_time_s - start_time_s)}, " # load graph
|
|
@@ -16,7 +16,7 @@ module QaServer::MonitorStatus
|
|
|
16
16
|
|
|
17
17
|
# @return [String] date of first recorded test run
|
|
18
18
|
def first_updated
|
|
19
|
-
QaServer::ScenarioRunRegistry.
|
|
19
|
+
QaServer::ScenarioRunRegistry.first_run_dt
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# @return [Integer] number of loaded authorities
|
|
@@ -10,6 +10,9 @@ module QaServer
|
|
|
10
10
|
self.performance_data_class = QaServer::PerformanceHistory
|
|
11
11
|
|
|
12
12
|
# Get hourly average for the past 24 hours.
|
|
13
|
+
# @param authority_name [String] limit statistics to records for the given authority (default: all authorities)
|
|
14
|
+
# @param action [Symbol] one of :search, :fetch, :all_actions
|
|
15
|
+
# @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
|
|
13
16
|
# @returns [Hash] performance statistics for the past 24 hours
|
|
14
17
|
# @example
|
|
15
18
|
# { 0: { hour: '1400', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
|
|
@@ -18,22 +21,19 @@ module QaServer
|
|
|
18
21
|
# ...,
|
|
19
22
|
# 23: { hour: 'NOW', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
|
|
20
23
|
# }
|
|
21
|
-
def average_last_24_hours(authority_name: nil, action: nil)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
data = {}
|
|
28
|
-
data[BY_HOUR] = performance_by_hour_label(idx, start_hour)
|
|
29
|
-
data[STATS] = stats
|
|
30
|
-
avgs[idx] = data
|
|
31
|
-
start_hour += 1.hour
|
|
24
|
+
def average_last_24_hours(authority_name: nil, action: nil, force: false)
|
|
25
|
+
Rails.cache.fetch("#{self.class}/#{__method__}/#{authority_name || ALL_AUTH}/#{action}/#{FOR_DAY}",
|
|
26
|
+
expires_in: QaServer.current_time.end_of_hour - QaServer.current_time,
|
|
27
|
+
race_condition_ttl: 1.hour, force: force) do
|
|
28
|
+
Rails.logger.info("#{self.class}##{__method__} - calculating performance stats for last 24 hours - cache expired or refresh requested (#{force})")
|
|
29
|
+
calculate_last_24_hours(authority_name, action)
|
|
32
30
|
end
|
|
33
|
-
avgs
|
|
34
31
|
end
|
|
35
32
|
|
|
36
33
|
# Get daily average for the past 30 days.
|
|
34
|
+
# @param authority_name [String] limit statistics to records for the given authority (default: all authorities)
|
|
35
|
+
# @param action [Symbol] one of :search, :fetch, :all_actions
|
|
36
|
+
# @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
|
|
37
37
|
# @returns [Hash] performance statistics for the past 30 days
|
|
38
38
|
# @example
|
|
39
39
|
# { 0: { day: '07-15-2019', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
|
|
@@ -42,22 +42,18 @@ module QaServer
|
|
|
42
42
|
# ...,
|
|
43
43
|
# 29: { day: 'TODAY', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
|
|
44
44
|
# }
|
|
45
|
-
def average_last_30_days(authority_name: nil, action: nil)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
|
|
51
|
-
data = {}
|
|
52
|
-
data[BY_DAY] = performance_by_day_label(idx, start_day)
|
|
53
|
-
data[STATS] = stats
|
|
54
|
-
avgs[idx] = data
|
|
55
|
-
start_day += 1.day
|
|
45
|
+
def average_last_30_days(authority_name: nil, action: nil, force: false)
|
|
46
|
+
Rails.cache.fetch("#{self.class}/#{__method__}/#{authority_name || ALL_AUTH}/#{action}/#{FOR_MONTH}",
|
|
47
|
+
expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
|
|
48
|
+
Rails.logger.info("#{self.class}##{__method__} - calculating performance stats for last 30 days - cache expired or refresh requested (#{force})")
|
|
49
|
+
calculate_last_30_days(authority_name, action)
|
|
56
50
|
end
|
|
57
|
-
avgs
|
|
58
51
|
end
|
|
59
52
|
|
|
60
53
|
# Get daily average for the past 12 months.
|
|
54
|
+
# @param authority_name [String] limit statistics to records for the given authority (default: all authorities)
|
|
55
|
+
# @param action [Symbol] one of :search, :fetch, :all_actions
|
|
56
|
+
# @param force [Boolean] if true, forces cache to regenerate; otherwise, returns value from cache unless expired
|
|
61
57
|
# @returns [Hash] performance statistics for the past 12 months
|
|
62
58
|
# @example
|
|
63
59
|
# { 0: { month: '09-2019', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }},
|
|
@@ -66,19 +62,12 @@ module QaServer
|
|
|
66
62
|
# ...,
|
|
67
63
|
# 11: { month: '08-2019', stats: { load_avg_ms: 12.3, normalization_avg_ms: 4.2, full_request_avg_ms: 16.5, etc. }}
|
|
68
64
|
# }
|
|
69
|
-
def average_last_12_months(authority_name: nil, action: nil)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
|
|
75
|
-
data = {}
|
|
76
|
-
data[BY_MONTH] = start_month.strftime("%m-%Y")
|
|
77
|
-
data[STATS] = stats
|
|
78
|
-
avgs[idx] = data
|
|
79
|
-
start_month += 1.month
|
|
65
|
+
def average_last_12_months(authority_name: nil, action: nil, force: false)
|
|
66
|
+
Rails.cache.fetch("#{self.class}/#{__method__}/#{authority_name || ALL_AUTH}/#{action}/#{FOR_YEAR}",
|
|
67
|
+
expires_in: QaServer.cache_expiry, race_condition_ttl: 1.hour, force: force) do
|
|
68
|
+
Rails.logger.info("#{self.class}##{__method__} - calculating performance stats for last 12 months - cache expired or refresh requested (#{force})")
|
|
69
|
+
calculate_last_12_months(authority_name, action)
|
|
80
70
|
end
|
|
81
|
-
avgs
|
|
82
71
|
end
|
|
83
72
|
|
|
84
73
|
private
|
|
@@ -109,6 +98,51 @@ module QaServer
|
|
|
109
98
|
""
|
|
110
99
|
end
|
|
111
100
|
end
|
|
101
|
+
|
|
102
|
+
def calculate_last_24_hours(authority_name, action)
|
|
103
|
+
start_hour = QaServer.current_time.beginning_of_hour - 23.hours
|
|
104
|
+
avgs = {}
|
|
105
|
+
0.upto(23).each do |idx|
|
|
106
|
+
records = records_by(authority_name, action, start_hour..start_hour.end_of_hour)
|
|
107
|
+
stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
|
|
108
|
+
data = {}
|
|
109
|
+
data[BY_HOUR] = performance_by_hour_label(idx, start_hour)
|
|
110
|
+
data[STATS] = stats
|
|
111
|
+
avgs[idx] = data
|
|
112
|
+
start_hour += 1.hour
|
|
113
|
+
end
|
|
114
|
+
avgs
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def calculate_last_30_days(authority_name, action)
|
|
118
|
+
start_day = QaServer.current_time.beginning_of_day - 29.days
|
|
119
|
+
avgs = {}
|
|
120
|
+
0.upto(29).each do |idx|
|
|
121
|
+
records = records_by(authority_name, action, start_day..start_day.end_of_day)
|
|
122
|
+
stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
|
|
123
|
+
data = {}
|
|
124
|
+
data[BY_DAY] = performance_by_day_label(idx, start_day)
|
|
125
|
+
data[STATS] = stats
|
|
126
|
+
avgs[idx] = data
|
|
127
|
+
start_day += 1.day
|
|
128
|
+
end
|
|
129
|
+
avgs
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def calculate_last_12_months(authority_name, action)
|
|
133
|
+
start_month = QaServer.current_time.beginning_of_month - 11.months
|
|
134
|
+
avgs = {}
|
|
135
|
+
0.upto(11).each do |idx|
|
|
136
|
+
records = records_by(authority_name, action, start_month..start_month.end_of_month)
|
|
137
|
+
stats = stats_calculator_class.new(records).calculate_stats(avg: true, full: false)
|
|
138
|
+
data = {}
|
|
139
|
+
data[BY_MONTH] = start_month.strftime("%m-%Y")
|
|
140
|
+
data[STATS] = stats
|
|
141
|
+
avgs[idx] = data
|
|
142
|
+
start_month += 1.month
|
|
143
|
+
end
|
|
144
|
+
avgs
|
|
145
|
+
end
|
|
112
146
|
end
|
|
113
147
|
end
|
|
114
148
|
end
|
|
@@ -73,4 +73,9 @@ QaServer.config do |config|
|
|
|
73
73
|
# impact and may need to be suppressed. Performance stats will not be gathered when this config is true.
|
|
74
74
|
# @param [Boolean] do not gather performance data when true (defaults to false for backward compatibitily)
|
|
75
75
|
# config.suppress_performance_gathering = false
|
|
76
|
+
|
|
77
|
+
# Performance data is gathered on every incoming query. Basic stats are logged from QA. Full stats are logged
|
|
78
|
+
# by QaServer and can eat up logging realestate. To suppress the logging of details, set this config to true.
|
|
79
|
+
# @param [Boolean] do not log performance data details when true (defaults to false for backward compatibitily)
|
|
80
|
+
# config.suppress_logging_performance_datails = false
|
|
76
81
|
end
|
|
@@ -179,6 +179,15 @@ module QaServer
|
|
|
179
179
|
@suppress_performance_gathering ||= false
|
|
180
180
|
end
|
|
181
181
|
|
|
182
|
+
# Performance data is gathered on every incoming query. Basic stats are logged from QA. Full stats are logged
|
|
183
|
+
# by QaServer and can eat up logging realestate. To suppress the logging of details, set this config to true.
|
|
184
|
+
# @param [Boolean] do not log performance data details when true (defaults to false for backward compatibitily)
|
|
185
|
+
attr_writer :suppress_logging_performance_datails
|
|
186
|
+
def suppress_logging_performance_datails
|
|
187
|
+
@suppress_logging_performance_datails ||= false
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# TODO: consider refactor performance caching to use Rails cache
|
|
182
191
|
def performance_cache
|
|
183
192
|
@performance_cache ||= QaServer::PerformanceCache.new
|
|
184
193
|
end
|
data/lib/qa_server/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: qa_server
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- E. Lynette Rayle
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-01-
|
|
11
|
+
date: 2020-01-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|