inferno_core 0.0.2 → 0.0.6

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/inferno/apps/web/controllers/test_runs/create.rb +30 -10
  3. data/lib/inferno/apps/web/controllers/test_runs/show.rb +10 -0
  4. data/lib/inferno/apps/web/controllers/test_sessions/create.rb +1 -0
  5. data/lib/inferno/apps/web/controllers/test_sessions/last_test_run.rb +22 -0
  6. data/lib/inferno/apps/web/controllers/test_sessions/results/index.rb +6 -1
  7. data/lib/inferno/apps/web/controllers/test_sessions/session_data/index.rb +21 -0
  8. data/lib/inferno/apps/web/router.rb +15 -0
  9. data/lib/inferno/apps/web/serializers/hash_value_extractor.rb +11 -0
  10. data/lib/inferno/apps/web/serializers/request.rb +1 -0
  11. data/lib/inferno/apps/web/serializers/result.rb +8 -0
  12. data/lib/inferno/apps/web/serializers/session_data.rb +10 -0
  13. data/lib/inferno/apps/web/serializers/test.rb +3 -6
  14. data/lib/inferno/apps/web/serializers/test_group.rb +5 -8
  15. data/lib/inferno/apps/web/serializers/test_run.rb +1 -0
  16. data/lib/inferno/apps/web/serializers/test_session.rb +1 -1
  17. data/lib/inferno/apps/web/serializers/test_suite.rb +1 -0
  18. data/lib/inferno/config/application.rb +5 -2
  19. data/lib/inferno/config/boot/db.rb +10 -1
  20. data/lib/inferno/config/boot/sidekiq.rb +11 -0
  21. data/lib/inferno/config/boot/suites.rb +4 -6
  22. data/lib/inferno/config/boot.rb +2 -0
  23. data/lib/inferno/db/migrations/001_create_initial_structure.rb +0 -21
  24. data/lib/inferno/db/migrations/002_add_wait_support.rb +7 -0
  25. data/lib/inferno/db/migrations/003_update_session_data.rb +18 -0
  26. data/lib/inferno/db/migrations/004_add_request_results_table.rb +9 -0
  27. data/lib/inferno/db/migrations/005_add_updated_at_index_to_results.rb +5 -0
  28. data/lib/inferno/db/schema.rb +154 -0
  29. data/lib/inferno/dsl/assertions.rb +20 -0
  30. data/lib/inferno/dsl/configurable.rb +126 -0
  31. data/lib/inferno/dsl/fhir_client.rb +4 -2
  32. data/lib/inferno/dsl/fhir_client_builder.rb +16 -0
  33. data/lib/inferno/dsl/http_client.rb +10 -8
  34. data/lib/inferno/dsl/request_storage.rb +30 -9
  35. data/lib/inferno/dsl/results.rb +49 -0
  36. data/lib/inferno/dsl/resume_test_route.rb +89 -0
  37. data/lib/inferno/dsl/runnable.rb +153 -16
  38. data/lib/inferno/dsl.rb +1 -3
  39. data/lib/inferno/entities/header.rb +7 -7
  40. data/lib/inferno/entities/message.rb +8 -6
  41. data/lib/inferno/entities/request.rb +42 -16
  42. data/lib/inferno/entities/result.rb +34 -18
  43. data/lib/inferno/entities/session_data.rb +33 -0
  44. data/lib/inferno/entities/test.rb +35 -8
  45. data/lib/inferno/entities/test_group.rb +8 -0
  46. data/lib/inferno/entities/test_run.rb +13 -6
  47. data/lib/inferno/entities/test_session.rb +8 -8
  48. data/lib/inferno/entities.rb +1 -1
  49. data/lib/inferno/exceptions.rb +24 -0
  50. data/lib/inferno/jobs/execute_test_run.rb +14 -0
  51. data/lib/inferno/jobs/resume_test_run.rb +14 -0
  52. data/lib/inferno/jobs.rb +16 -0
  53. data/lib/inferno/public/bundle.js +1 -1
  54. data/lib/inferno/repositories/repository.rb +13 -0
  55. data/lib/inferno/repositories/requests.rb +5 -4
  56. data/lib/inferno/repositories/results.rb +151 -3
  57. data/lib/inferno/repositories/session_data.rb +47 -0
  58. data/lib/inferno/repositories/test_runs.rb +81 -0
  59. data/lib/inferno/test_runner.rb +125 -31
  60. data/lib/inferno/utils/markdown_formatter.rb +15 -0
  61. data/lib/inferno/utils/middleware/request_logger.rb +16 -3
  62. data/lib/inferno/version.rb +1 -1
  63. data/lib/inferno.rb +4 -0
  64. data/spec/factories/header.rb +19 -0
  65. data/spec/factories/message.rb +17 -0
  66. data/spec/factories/request.rb +42 -0
  67. data/spec/factories/result.rb +45 -0
  68. data/spec/factories/test_run.rb +24 -0
  69. data/spec/factories/test_session.rb +11 -0
  70. data/spec/fixtures/basic_test_group.rb +9 -0
  71. data/spec/fixtures/basic_test_suite.rb +8 -0
  72. metadata +57 -5
  73. data/lib/inferno/dsl/fhir_manipulation.rb +0 -25
  74. data/lib/inferno/entities/test_input.rb +0 -20
@@ -80,6 +80,19 @@ module Inferno
80
80
  build_entity(result.to_hash.merge(handle_non_db_params(params)))
81
81
  end
82
82
 
83
+ # Update a record in the database.
84
+ #
85
+ # @param entity_id [String]
86
+ # @param params [Hash]
87
+ # @example
88
+ # repo = Inferno::Repositories::SomeEntities.new
89
+ # result = repo.update(id, key1: 'value1', key2: 'value2')
90
+ def update(entity_id, params = {})
91
+ self.class::Model
92
+ .find(id: entity_id)
93
+ .update(params.merge(updated_at: Time.now))
94
+ end
95
+
83
96
  # Creates an instance of the entity associated with this repository.
84
97
  # Override if any special logic is required to create the entity.
85
98
  #
@@ -7,13 +7,13 @@ module Inferno
7
7
  request = self.class::Model.create(db_params(params))
8
8
 
9
9
  request_headers = (params[:request_headers] || []).map do |header|
10
- headers_repo.create(header.merge(request_id: request.index, type: 'request'))
10
+ request.add_header(header.merge(request_id: request.index, type: 'request'))
11
11
  end
12
12
  response_headers = (params[:response_headers] || []).map do |header|
13
- headers_repo.create(header.merge(request_id: request.index, type: 'response'))
13
+ request.add_header(header.merge(request_id: request.index, type: 'response'))
14
14
  end
15
15
 
16
- headers = request_headers + response_headers
16
+ headers = (request_headers + response_headers).map { |header| headers_repo.build_entity(header.to_hash) }
17
17
 
18
18
  build_entity(
19
19
  request.to_hash
@@ -73,7 +73,8 @@ module Inferno
73
73
  end
74
74
 
75
75
  class Model < Sequel::Model(db)
76
- many_to_one :result, class: 'Inferno::Repositories::Results::Model', key: :result_id
76
+ many_to_many :result, class: 'Inferno::Repositories::Results::Model', join_table: :requests_results,
77
+ left_key: :request_id, right_key: :result_id
77
78
  one_to_many :headers, class: 'Inferno::Repositories::Headers::Model', key: :request_id
78
79
 
79
80
  def before_create
@@ -15,11 +15,43 @@ module Inferno
15
15
  messages = params.delete(:messages) || []
16
16
  requests = params.delete(:requests) || []
17
17
  super(params).tap do |result|
18
+ result_model = self.class::Model.find(id: result.id)
18
19
  messages.each { |message| messages_repo.create(message.merge(result_id: result.id)) }
19
- requests.each { |request| requests_repo.create(request.to_hash.merge(result_id: result.id)) }
20
+ requests.each do |request|
21
+ request_id =
22
+ if request.id.present?
23
+ request.id
24
+ else
25
+ requests_repo.create(request.to_hash.merge(result_id: result.id)).id
26
+ end
27
+ request_model = requests_repo.class::Model.find(id: request_id)
28
+ result_model.add_request(request_model)
29
+ end
20
30
  end
21
31
  end
22
32
 
33
+ # Get the current result for a particular test/group
34
+ # @api private
35
+ # @example
36
+ # repo.current_result_for_test_session(
37
+ # test_session_id,
38
+ # test_id: 'test_id'
39
+ # )
40
+ def current_result_for_test_session(test_session_id, **params)
41
+ self.class::Model
42
+ .where({ test_session_id: test_session_id }.merge(params))
43
+ .order(Sequel.desc(:updated_at))
44
+ .limit(1)
45
+ .all
46
+ .map! do |result_hash|
47
+ build_entity(
48
+ result_hash
49
+ .to_json_data(json_serializer_options)
50
+ .deep_symbolize_keys!
51
+ )
52
+ end.first
53
+ end
54
+
23
55
  def build_entity(params)
24
56
  runnable =
25
57
  if params[:test_id]
@@ -34,12 +66,85 @@ module Inferno
34
66
  entity_class.new(params.merge(runnable))
35
67
  end
36
68
 
69
+ def result_for_test_run(test_run_id:, **params)
70
+ result_hash =
71
+ self.class::Model
72
+ .find({ test_run_id: test_run_id }.merge(params))
73
+ &.to_hash
74
+
75
+ return nil if result_hash.nil?
76
+
77
+ build_entity(result_hash)
78
+ end
79
+
80
+ def test_run_results_after(test_run_id:, after:)
81
+ Model
82
+ .where(test_run_id: test_run_id)
83
+ .where { updated_at >= after }
84
+ .to_a
85
+ .map! do |result_hash|
86
+ build_entity(
87
+ result_hash
88
+ .to_json_data(json_serializer_options)
89
+ .deep_symbolize_keys!
90
+ )
91
+ end
92
+ end
93
+
94
+ def find_waiting_result(test_run_id:)
95
+ result_hash =
96
+ Model
97
+ .where(test_run_id: test_run_id, result: 'wait')
98
+ .where { test_id !~ nil }
99
+ .limit(1)
100
+ .to_a
101
+ .first
102
+ &.to_hash
103
+
104
+ return nil if result_hash.nil?
105
+
106
+ build_entity(result_hash)
107
+ end
108
+
109
+ # Get all of the current results for a test session
110
+ def current_results_for_test_session(test_session_id)
111
+ self.class::Model
112
+ .current_results_for_test_session(test_session_id)
113
+ .eager(:messages)
114
+ .eager(requests: proc { |requests| requests.select(*Entities::Request::SUMMARY_FIELDS) })
115
+ .all
116
+ .map! do |result_hash|
117
+ build_entity(
118
+ result_hash
119
+ .to_json_data(json_serializer_options)
120
+ .deep_symbolize_keys!
121
+ )
122
+ end
123
+ end
124
+
125
+ # Get the current results for a list of runnables
126
+ def current_results_for_test_session_and_runnables(test_session_id, runnables)
127
+ self.class::Model
128
+ .current_results_for_test_session_and_runnables(test_session_id, runnables)
129
+ .all
130
+ .map! do |result_hash|
131
+ build_entity(
132
+ result_hash
133
+ .to_json_data(json_serializer_options)
134
+ .deep_symbolize_keys!
135
+ )
136
+ end
137
+ end
138
+
139
+ def pass_waiting_result(result_id, message = nil)
140
+ update(result_id, result: 'pass', result_message: message)
141
+ end
142
+
37
143
  def json_serializer_options
38
144
  {
39
145
  include: {
40
146
  messages: {},
41
147
  requests: {
42
- include: { headers: {} },
43
148
  only: Entities::Request::SUMMARY_FIELDS
44
149
  }
45
150
  }
@@ -49,8 +154,33 @@ module Inferno
49
154
  class Model < Sequel::Model(db)
50
155
  include ValidateRunnableReference
51
156
 
157
+ def self.current_results_sql(with_runnables_filter: false)
158
+ query = <<~SQL.gsub(/\s+/, ' ').freeze
159
+ SELECT * FROM results a
160
+ WHERE test_session_id = :test_session_id
161
+ SQL
162
+ runnables_filter = <<~SQL.gsub(/\s+/, ' ').freeze
163
+ AND (test_id IN :test_ids OR test_group_id IN :test_group_ids OR test_suite_id IN :test_suite_ids)
164
+ SQL
165
+ subquery = <<~SQL.gsub(/\s+/, ' ').freeze
166
+ AND a.id IN (
167
+ SELECT id
168
+ FROM results b
169
+ WHERE (b.test_session_id = a.test_session_id AND b.test_id = a.test_id) OR
170
+ (b.test_session_id = a.test_session_id AND b.test_group_id = a.test_group_id) OR
171
+ (b.test_session_id = a.test_session_id AND b.test_suite_id = a.test_suite_id)
172
+ ORDER BY updated_at DESC
173
+ LIMIT 1
174
+ )
175
+ SQL
176
+ return "#{query} #{runnables_filter} #{subquery}" if with_runnables_filter
177
+
178
+ "#{query} #{subquery}"
179
+ end
180
+
52
181
  one_to_many :messages, class: 'Inferno::Repositories::Messages::Model', key: :result_id
53
- one_to_many :requests, class: 'Inferno::Repositories::Requests::Model', key: :result_id
182
+ many_to_many :requests, class: 'Inferno::Repositories::Requests::Model', join_table: :requests_results,
183
+ left_key: :results_id, right_key: :requests_id
54
184
  many_to_one :test_run, class: 'Inferno::Repositories::TestRuns::Model', key: :test_run_id
55
185
  many_to_one :test_session, class: 'Inferno::Repositories::TestSessions::Model', key: :test_session_id
56
186
 
@@ -66,6 +196,24 @@ module Inferno
66
196
  super
67
197
  errors.add(:result, "'#{result}' is not valid") unless Entities::Result::RESULT_OPTIONS.include?(result)
68
198
  end
199
+
200
+ def self.current_results_for_test_session(test_session_id)
201
+ fetch(current_results_sql, test_session_id: test_session_id)
202
+ end
203
+
204
+ def self.current_results_for_test_session_and_runnables(test_session_id, runnables)
205
+ test_ids = runnables.select { |runnable| runnable < Entities::Test }.map!(&:id)
206
+ test_group_ids = runnables.select { |runnable| runnable < Entities::TestGroup }.map!(&:id)
207
+ test_suite_ids = runnables.select { |runnable| runnable < Entities::TestSuite }.map!(&:id)
208
+
209
+ fetch(
210
+ current_results_sql(with_runnables_filter: true),
211
+ test_session_id: test_session_id,
212
+ test_ids: test_ids,
213
+ test_group_ids: test_group_ids,
214
+ test_suite_ids: test_suite_ids
215
+ )
216
+ end
69
217
  end
70
218
  end
71
219
  end
@@ -0,0 +1,47 @@
1
+ module Inferno
2
+ module Repositories
3
+ class SessionData < Repository
4
+ def save(params)
5
+ name = params[:name].to_s.downcase
6
+ test_session_id = params[:test_session_id]
7
+ db
8
+ .insert_conflict(
9
+ target: :id,
10
+ update: { value: params[:value] }
11
+ ).insert(
12
+ id: "#{test_session_id}_#{name}",
13
+ name: name,
14
+ value: params[:value],
15
+ test_session_id: test_session_id
16
+ )
17
+ end
18
+
19
+ def load(test_session_id:, name:)
20
+ self.class::Model
21
+ .find(test_session_id: test_session_id, name: name.to_s.downcase)
22
+ &.value
23
+ end
24
+
25
+ def get_all_from_session(test_session_id)
26
+ self.class::Model
27
+ .where(test_session_id: test_session_id)
28
+ .all
29
+ .map! do |session_data_hash|
30
+ build_entity(
31
+ session_data_hash
32
+ .to_json_data
33
+ .deep_symbolize_keys!
34
+ )
35
+ end
36
+ end
37
+
38
+ def entity_class_name
39
+ 'SessionData'
40
+ end
41
+
42
+ class Model < Sequel::Model(db)
43
+ many_to_one :test_session, class: 'Inferno::Repositories::TestSessions::Model', key: :test_session_id
44
+ end
45
+ end
46
+ end
47
+ end
@@ -13,6 +13,14 @@ module Inferno
13
13
  }
14
14
  end
15
15
 
16
+ def build_entity(params)
17
+ super.tap do |test_run|
18
+ test_run&.results&.map! do |result|
19
+ result.is_a?(Entities::Result) ? result : Entities::Result.new(result)
20
+ end
21
+ end
22
+ end
23
+
16
24
  def results_for_test_run(test_run_id)
17
25
  test_run_hash =
18
26
  self.class::Model
@@ -24,6 +32,65 @@ module Inferno
24
32
  .map! { |result| results_repo.build_entity(result) }
25
33
  end
26
34
 
35
+ def find_latest_waiting_by_identifier(identifier)
36
+ test_run_hash =
37
+ self.class::Model
38
+ .where(status: 'waiting')
39
+ .where(identifier: identifier)
40
+ .where { wait_timeout >= Time.now }
41
+ .order(Sequel.desc(:updated_at))
42
+ .limit(1)
43
+ .to_a
44
+ &.first
45
+ &.to_hash
46
+
47
+ return nil if test_run_hash.nil?
48
+
49
+ build_entity(test_run_hash)
50
+ end
51
+
52
+ def last_test_run(test_session_id)
53
+ test_run_hash =
54
+ self.class::Model
55
+ .where(test_session_id: test_session_id)
56
+ .order(Sequel.desc(:updated_at))
57
+ .limit(1)
58
+ .to_a
59
+ .map { |record| record.to_json_data(json_serializer_options).deep_symbolize_keys! }
60
+ &.first
61
+ &.to_hash
62
+
63
+ return nil if test_run_hash.nil?
64
+
65
+ build_entity(test_run_hash)
66
+ end
67
+
68
+ def mark_as_running(test_run_id)
69
+ update(test_run_id, status: 'running')
70
+ end
71
+
72
+ def mark_as_done(test_run_id)
73
+ update(test_run_id, status: 'done')
74
+ end
75
+
76
+ def mark_as_waiting(test_run_id, identifier, timeout)
77
+ update(
78
+ test_run_id,
79
+ status: 'waiting',
80
+ identifier: identifier,
81
+ wait_timeout: Time.now + timeout.seconds
82
+ )
83
+ end
84
+
85
+ def mark_as_no_longer_waiting(test_run_id)
86
+ update(
87
+ test_run_id,
88
+ status: 'queued',
89
+ identifier: nil,
90
+ wait_timeout: nil
91
+ )
92
+ end
93
+
27
94
  class Model < Sequel::Model(db)
28
95
  include ValidateRunnableReference
29
96
 
@@ -33,6 +100,13 @@ module Inferno
33
100
  key: :test_run_id
34
101
  many_to_one :test_session, class: 'Inferno::Repositories::TestSessions::Model', key: :test_session_id
35
102
 
103
+ def validate
104
+ super
105
+ if status.present? && !Entities::TestRun::STATUS_OPTIONS.include?(status) # rubocop:disable Style/GuardClause
106
+ errors.add(:status, "'#{status}' is not valid")
107
+ end
108
+ end
109
+
36
110
  def before_create
37
111
  self.id = SecureRandom.uuid
38
112
  time = Time.now
@@ -41,6 +115,13 @@ module Inferno
41
115
  super
42
116
  end
43
117
  end
118
+
119
+ def active_test_run_for_session?(test_session_id)
120
+ self.class::Model
121
+ .where(test_session_id: test_session_id)
122
+ .exclude(status: 'done')
123
+ .count.positive?
124
+ end
44
125
  end
45
126
  end
46
127
  end
@@ -1,73 +1,167 @@
1
+ require_relative './utils/markdown_formatter'
2
+
1
3
  module Inferno
2
4
  # @api private
3
5
  class TestRunner
4
- attr_reader :test_session, :test_run
6
+ include Inferno::Utils::MarkdownFormatter
7
+ attr_reader :test_session, :test_run, :resuming
5
8
 
6
- def initialize(test_session:, test_run:)
9
+ def initialize(test_session:, test_run:, resume: false)
7
10
  @test_session = test_session
8
11
  @test_run = test_run
12
+ @resuming = resume
13
+ end
14
+
15
+ def run_results
16
+ @run_results ||= {}
9
17
  end
10
18
 
11
19
  def results_repo
12
20
  @results_repo ||= Repositories::Results.new
13
21
  end
14
22
 
15
- def run(runnable, inputs = {}, outputs = {})
23
+ def test_runs_repo
24
+ @test_runs_repo ||= Repositories::TestRuns.new
25
+ end
26
+
27
+ def session_data_repo
28
+ @session_data_repo ||= Repositories::SessionData.new
29
+ end
30
+
31
+ def start
32
+ test_runs_repo.mark_as_running(test_run.id)
33
+
34
+ run(test_run.runnable)
35
+
36
+ test_runs_repo.mark_as_done(test_run.id) unless run_results.values.any?(&:waiting?)
37
+
38
+ run_results.values
39
+ end
40
+
41
+ def run(runnable, scratch = {})
16
42
  if runnable < Entities::Test
17
- run_test(runnable, inputs, outputs)
43
+ return existing_test_result(runnable) || run_test(runnable, scratch) if resuming
44
+
45
+ run_test(runnable, scratch)
18
46
  else
19
- run_group(runnable, inputs, outputs)
47
+ run_group(runnable, scratch)
20
48
  end
21
49
  end
22
50
 
23
- def run_test(runnable, inputs = {}, outputs = {})
24
- test_instance = runnable.new(inputs: inputs.merge(outputs), test_session_id: test_session.id)
51
+ def existing_test_result(runnable)
52
+ results_repo.result_for_test_run(runnable.reference_hash.merge(test_run_id: test_run.id))
53
+ end
54
+
55
+ def run_test(test, scratch)
56
+ inputs = load_inputs(test)
57
+
58
+ input_json_string = JSON.generate(inputs)
59
+ test_instance = test.new(inputs: inputs, test_session_id: test_session.id, scratch: scratch)
25
60
 
26
61
  result = begin
27
- inputs.merge(outputs).each do |key, value|
28
- test_instance.instance_variable_set("@#{key}", value)
29
- end
30
62
  test_instance.load_named_requests
31
- test_instance.instance_eval(&runnable.block)
63
+ test_instance.instance_eval(&test.block)
32
64
  'pass'
33
65
  rescue Exceptions::TestResultException => e
34
- test_instance.result_message = e.message
66
+ test_instance.result_message = format_markdown(e.message)
35
67
  e.result
36
68
  rescue StandardError => e
37
- test_instance.result_message = "Error: #{e.message}"
69
+ Application['logger'].error(e.full_message)
70
+ test_instance.result_message = format_markdown("Error: #{e.message}\n\n#{e.backtrace.first}")
38
71
  'error'
39
72
  end
40
73
 
41
- runnable.outputs.each do |output|
42
- outputs[output] = test_instance.send(output)
74
+ outputs = save_outputs(test_instance)
75
+ output_json_string = JSON.generate(outputs)
76
+
77
+ if result == 'wait'
78
+ test_runs_repo.mark_as_waiting(test_run.id, test_instance.identifier, test_instance.wait_timeout)
43
79
  end
44
80
 
45
- [persist_result(
81
+ test_result = persist_result(
46
82
  {
47
- test_session_id: test_session.id,
48
- test_run_id: test_run.id,
49
83
  messages: test_instance.messages,
50
84
  requests: test_instance.requests,
51
85
  result: result,
52
- result_message: test_instance.result_message
53
- }.merge(runnable.reference_hash)
54
- )]
86
+ result_message: test_instance.result_message,
87
+ input_json: input_json_string,
88
+ output_json: output_json_string
89
+ }.merge(test.reference_hash)
90
+ )
91
+
92
+ # If running a single test, update its parents' results. If running a
93
+ # group or suite, #run_group handles updating the parents.
94
+ return test_result if test_run.test_id.blank?
95
+
96
+ update_parent_result(test.parent)
97
+
98
+ test_result
99
+ end
100
+
101
+ def run_group(group, scratch)
102
+ results = []
103
+ group.children.each do |child|
104
+ result = run(child, scratch)
105
+ results << result
106
+ break if results.last.waiting?
107
+ end
108
+
109
+ results.flatten!
110
+
111
+ group_result = persist_result(group.reference_hash.merge(result: roll_up_result(results)))
112
+
113
+ update_parent_result(group.parent)
114
+
115
+ group_result
55
116
  end
56
117
 
57
- def run_group(runnable, inputs = {}, outputs = {})
58
- results = runnable.children.flat_map { |child| run(child, inputs, outputs) }
118
+ def update_parent_result(parent)
119
+ return if parent.nil?
59
120
 
60
- results << persist_result(
61
- {
62
- test_session_id: test_session.id,
63
- test_run_id: test_run.id,
64
- result: roll_up_result(results)
65
- }.merge(runnable.reference_hash)
66
- )
121
+ children = parent.children
122
+ child_results = results_repo.current_results_for_test_session_and_runnables(test_session.id, children)
123
+ return if children.length != child_results.length
124
+
125
+ old_result = results_repo.current_result_for_test_session(test_session.id, parent.reference_hash)&.result
126
+ new_result = roll_up_result(child_results)
127
+
128
+ if new_result != old_result
129
+ persist_result(parent.reference_hash.merge(result: new_result))
130
+
131
+ update_parent_result(parent.parent)
132
+ end
133
+
134
+ new_result
135
+ end
136
+
137
+ def load_inputs(runnable)
138
+ runnable.inputs.each_with_object({}) do |input_identifier, input_hash|
139
+ input_alias = runnable.config.input_name(input_identifier)
140
+ input_hash[input_identifier] = session_data_repo.load(test_session_id: test_session.id, name: input_alias)
141
+ end
142
+ end
143
+
144
+ def save_outputs(runnable_instance)
145
+ outputs =
146
+ runnable_instance.outputs_to_persist.map do |output_identifier, value|
147
+ {
148
+ name: runnable_instance.class.config.output_name(output_identifier),
149
+ value: value
150
+ }
151
+ end
152
+
153
+ outputs.compact!
154
+ outputs.each do |output|
155
+ session_data_repo.save(output.merge(test_session_id: test_session.id))
156
+ end
67
157
  end
68
158
 
69
159
  def persist_result(params)
70
- results_repo.create(params)
160
+ result = results_repo.create(
161
+ params.merge(test_run_id: test_run.id, test_session_id: test_session.id)
162
+ )
163
+
164
+ run_results[result.runnable.id] = result
71
165
  end
72
166
 
73
167
  def roll_up_result(results)
@@ -0,0 +1,15 @@
1
+ module Inferno
2
+ module Utils
3
+ # @api private
4
+ module MarkdownFormatter
5
+ def format_markdown(markdown) # rubocop:disable Metrics/CyclomaticComplexity
6
+ lines = markdown.lines
7
+
8
+ return markdown if lines.any? { |line| line.match?(/^\S/) }
9
+
10
+ natural_indent = lines.collect { |l| l.index(/[^ ]/) }.select { |l| !l.nil? && l.positive? }.min || 0
11
+ markdown.lines.map { |l| l[natural_indent..] || "\n" }.join
12
+ end
13
+ end
14
+ end
15
+ end
@@ -29,11 +29,17 @@ module Inferno
29
29
 
30
30
  def log_response(response, start_time, end_time, exception = nil)
31
31
  elapsed = end_time - start_time
32
- status, _response_headers, response_body = response if response
32
+ status, _response_headers, body = response if response
33
33
  status, = response if exception
34
34
 
35
35
  logger.info("#{status} in #{elapsed.in_milliseconds} ms")
36
- logger.info(response_body)
36
+ return unless body.present?
37
+
38
+ if body.length > 100
39
+ logger.info("#{body[0..100]}...")
40
+ else
41
+ logger.info(body)
42
+ end
37
43
  end
38
44
 
39
45
  def log_request(env)
@@ -47,7 +53,14 @@ module Inferno
47
53
  query_string = query.blank? ? '' : "?#{query}"
48
54
 
49
55
  logger.info("#{method} #{scheme}://#{host}#{path}#{query_string}")
50
- logger.info(body) if body.present?
56
+
57
+ return unless body.present?
58
+
59
+ if body.length > 100
60
+ logger.info("#{body[0..100]}...")
61
+ else
62
+ logger.info(body)
63
+ end
51
64
  end
52
65
  end
53
66
  end
@@ -1,3 +1,3 @@
1
1
  module Inferno
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.6'.freeze
3
3
  end
data/lib/inferno.rb CHANGED
@@ -6,10 +6,14 @@ require_relative 'inferno/config/application'
6
6
  require_relative 'inferno/dsl'
7
7
  require_relative 'inferno/entities'
8
8
  require_relative 'inferno/exceptions'
9
+ require_relative 'inferno/jobs'
9
10
  require_relative 'inferno/repositories'
10
11
  require_relative 'inferno/spec_support'
11
12
  require_relative 'inferno/test_runner'
12
13
  require_relative 'inferno/version'
13
14
 
14
15
  module Inferno
16
+ def self.routes
17
+ @routes ||= []
18
+ end
15
19
  end
@@ -0,0 +1,19 @@
1
+ FactoryBot.define do
2
+ factory :header, class: 'Inferno::Entities::Header' do
3
+ request
4
+
5
+ request_id { request.index }
6
+
7
+ sequence(:name) { |n| "HEADER NAME #{n}" }
8
+
9
+ sequence(:value) { |n| "HEADER VALUE #{n}" }
10
+
11
+ sequence(:type) { |n| n.even? ? 'request' : 'response' }
12
+
13
+ initialize_with { new(**attributes) }
14
+
15
+ to_create do |instance|
16
+ Inferno::Repositories::Headers.new.create(instance.to_hash)
17
+ end
18
+ end
19
+ end