inferno_core 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/bin/inferno-console +8 -0
- data/lib/inferno.rb +15 -0
- data/lib/inferno/apps/web/application.rb +12 -0
- data/lib/inferno/apps/web/controllers/controller.rb +34 -0
- data/lib/inferno/apps/web/controllers/requests/show.rb +16 -0
- data/lib/inferno/apps/web/controllers/test_runs/create.rb +39 -0
- data/lib/inferno/apps/web/controllers/test_runs/results/index.rb +18 -0
- data/lib/inferno/apps/web/controllers/test_runs/show.rb +16 -0
- data/lib/inferno/apps/web/controllers/test_sessions/create.rb +26 -0
- data/lib/inferno/apps/web/controllers/test_sessions/results/index.rb +17 -0
- data/lib/inferno/apps/web/controllers/test_sessions/show.rb +16 -0
- data/lib/inferno/apps/web/controllers/test_suites/index.rb +13 -0
- data/lib/inferno/apps/web/controllers/test_suites/show.rb +16 -0
- data/lib/inferno/apps/web/router.rb +27 -0
- data/lib/inferno/apps/web/serializers/header.rb +12 -0
- data/lib/inferno/apps/web/serializers/input.rb +16 -0
- data/lib/inferno/apps/web/serializers/message.rb +10 -0
- data/lib/inferno/apps/web/serializers/request.rb +26 -0
- data/lib/inferno/apps/web/serializers/result.rb +21 -0
- data/lib/inferno/apps/web/serializers/serializer.rb +16 -0
- data/lib/inferno/apps/web/serializers/test.rb +17 -0
- data/lib/inferno/apps/web/serializers/test_group.rb +23 -0
- data/lib/inferno/apps/web/serializers/test_run.rb +19 -0
- data/lib/inferno/apps/web/serializers/test_session.rb +17 -0
- data/lib/inferno/apps/web/serializers/test_suite.rb +18 -0
- data/lib/inferno/config/application.rb +22 -0
- data/lib/inferno/config/boot.rb +5 -0
- data/lib/inferno/config/boot/db.rb +23 -0
- data/lib/inferno/config/boot/logging.rb +16 -0
- data/lib/inferno/config/boot/suites.rb +27 -0
- data/lib/inferno/config/boot/web.rb +17 -0
- data/lib/inferno/db/migrations/001_create_initial_structure.rb +165 -0
- data/lib/inferno/dsl.rb +35 -0
- data/lib/inferno/dsl/assertions.rb +93 -0
- data/lib/inferno/dsl/fhir_client.rb +152 -0
- data/lib/inferno/dsl/fhir_client_builder.rb +56 -0
- data/lib/inferno/dsl/fhir_manipulation.rb +25 -0
- data/lib/inferno/dsl/fhir_validation.rb +111 -0
- data/lib/inferno/dsl/http_client.rb +122 -0
- data/lib/inferno/dsl/http_client_builder.rb +54 -0
- data/lib/inferno/dsl/request_storage.rb +101 -0
- data/lib/inferno/dsl/results.rb +54 -0
- data/lib/inferno/dsl/runnable.rb +250 -0
- data/lib/inferno/entities.rb +19 -0
- data/lib/inferno/entities/attributes.rb +9 -0
- data/lib/inferno/entities/entity.rb +15 -0
- data/lib/inferno/entities/header.rb +42 -0
- data/lib/inferno/entities/message.rb +22 -0
- data/lib/inferno/entities/request.rb +166 -0
- data/lib/inferno/entities/result.rb +49 -0
- data/lib/inferno/entities/test.rb +173 -0
- data/lib/inferno/entities/test_group.rb +87 -0
- data/lib/inferno/entities/test_input.rb +20 -0
- data/lib/inferno/entities/test_run.rb +63 -0
- data/lib/inferno/entities/test_session.rb +26 -0
- data/lib/inferno/entities/test_suite.rb +73 -0
- data/lib/inferno/exceptions.rb +42 -0
- data/lib/inferno/public/217.bundle.js +1 -0
- data/lib/inferno/public/assets.json +6 -0
- data/lib/inferno/public/bundle.js +2 -0
- data/lib/inferno/public/bundle.js.LICENSE.txt +65 -0
- data/lib/inferno/public/e09b16f5cb645eb05f90c8f38f3409fb.png +0 -0
- data/lib/inferno/public/favicon.ico +0 -0
- data/lib/inferno/public/logo192.png +0 -0
- data/lib/inferno/public/logo512.png +0 -0
- data/lib/inferno/repositories.rb +27 -0
- data/lib/inferno/repositories/headers.rb +22 -0
- data/lib/inferno/repositories/in_memory_repository.rb +41 -0
- data/lib/inferno/repositories/messages.rb +35 -0
- data/lib/inferno/repositories/repository.rb +106 -0
- data/lib/inferno/repositories/requests.rb +89 -0
- data/lib/inferno/repositories/results.rb +72 -0
- data/lib/inferno/repositories/test_groups.rb +9 -0
- data/lib/inferno/repositories/test_runs.rb +46 -0
- data/lib/inferno/repositories/test_sessions.rb +56 -0
- data/lib/inferno/repositories/test_suites.rb +9 -0
- data/lib/inferno/repositories/tests.rb +9 -0
- data/lib/inferno/repositories/validate_runnable_reference.rb +42 -0
- data/lib/inferno/spec_support.rb +9 -0
- data/lib/inferno/test_runner.rb +81 -0
- data/lib/inferno/utils/middleware/request_logger.rb +55 -0
- data/lib/inferno/version.rb +3 -0
- data/spec/support/factory_bot.rb +21 -0
- metadata +514 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module Repositories
|
5
|
+
class InMemoryRepository
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators 'self.class', :all, :all_by_id
|
9
|
+
|
10
|
+
def insert(klass)
|
11
|
+
all << klass
|
12
|
+
end
|
13
|
+
|
14
|
+
def find(id)
|
15
|
+
all_by_id[id.to_s]
|
16
|
+
end
|
17
|
+
|
18
|
+
def exists?(id)
|
19
|
+
all_by_id.include? id
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def all
|
24
|
+
@all ||= []
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def all_by_id
|
29
|
+
@all_by_id ||= {}
|
30
|
+
@all_by_id.length == all.length ? @all_by_id : index_by_id
|
31
|
+
end
|
32
|
+
|
33
|
+
def index_by_id
|
34
|
+
@all_by_id = {}
|
35
|
+
all.each { |klass| @all_by_id[klass.id] = klass }
|
36
|
+
@all_by_id
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Inferno
|
2
|
+
module Repositories
|
3
|
+
class Messages < Repository
|
4
|
+
def messages_for_result(result_id)
|
5
|
+
self.class::Model
|
6
|
+
.order(:index)
|
7
|
+
.where(result_id: result_id)
|
8
|
+
.to_a
|
9
|
+
.map!(&:to_json_data)
|
10
|
+
.each(&:deep_symbolize_keys!)
|
11
|
+
.map! { |result| build_entity(result) }
|
12
|
+
end
|
13
|
+
|
14
|
+
class Model < Sequel::Model(db)
|
15
|
+
many_to_one :result, class: 'Inferno::Repositories::Results::Model', key: :result_id
|
16
|
+
|
17
|
+
def before_create
|
18
|
+
self.id = SecureRandom.uuid
|
19
|
+
time = Time.now
|
20
|
+
self.created_at ||= time
|
21
|
+
self.updated_at ||= time
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate
|
26
|
+
super
|
27
|
+
types = Entities::Message::TYPES
|
28
|
+
errors.add(:message, 'must be present') if message.blank?
|
29
|
+
errors.add(:type, 'must be present') if type.blank?
|
30
|
+
errors.add(:type, "'#{type}' is invalid. Must be one of: #{types.join(', ')}") unless types.include?(type)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Inferno
|
2
|
+
module Repositories
|
3
|
+
# Base class for repositories. Subclass and override methods as
|
4
|
+
# needed.
|
5
|
+
#
|
6
|
+
# @abstract
|
7
|
+
class Repository
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
def_delegators 'self.class', :db, :table_name
|
11
|
+
|
12
|
+
# Return the db connection for this repository.
|
13
|
+
def self.db
|
14
|
+
Application['db.connection'][table_name]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return the name of the database table for this repository. Override if
|
18
|
+
# the table name is not the snake case version of the name of the
|
19
|
+
# repository class.
|
20
|
+
#
|
21
|
+
# @return [String]
|
22
|
+
def self.table_name
|
23
|
+
name.demodulize.underscore.to_sym
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return the name of the entity class which will be instantiated by a
|
27
|
+
# repository. Override if the entity class name is not the singular
|
28
|
+
# version of the repository name.
|
29
|
+
#
|
30
|
+
# @return [Class]
|
31
|
+
def entity_class_name
|
32
|
+
self.class.name.demodulize.singularize
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return the class of the entity which will be instantiated by a
|
36
|
+
# repository. Override if the entity class is not in the
|
37
|
+
# `Inferno::Entities` namespace.
|
38
|
+
#
|
39
|
+
# @return [Class]
|
40
|
+
def entity_class
|
41
|
+
Entities.const_get(entity_class_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Find a database record by id, and instantiate an entity from that
|
45
|
+
# record.
|
46
|
+
#
|
47
|
+
# @param id [String]
|
48
|
+
# @return [Inferno::Entities] an instance of the class returned by
|
49
|
+
# `#entity_class`
|
50
|
+
def find(id)
|
51
|
+
result = self.class::Model.find(id: id)
|
52
|
+
return result if result.nil?
|
53
|
+
|
54
|
+
build_entity(result.to_hash)
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_non_db_entities(hash)
|
58
|
+
if hash.include? :test_id
|
59
|
+
hash[:test] = Tests.new.find(hash[:test_id])
|
60
|
+
elsif hash.include? :test_group_id
|
61
|
+
hash[:test_group] = TestGroups.new.find(hash[:test_group_id])
|
62
|
+
elsif hash.include? :test_suite_id
|
63
|
+
hash[:test_suite] = TestSuites.new.find(hash[:test_suite_id])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Create a new record in the database.
|
68
|
+
#
|
69
|
+
# @param params [Hash]
|
70
|
+
# @return [Inferno::Entities] an instance of the entity for this repo
|
71
|
+
# @example
|
72
|
+
# repo = Inferno::Repositories::SomeEntities.new
|
73
|
+
# begin
|
74
|
+
# result = repo.create(key1: 'value1', key2: 'value2')
|
75
|
+
# rescue Sequel::ValidationFailed => e
|
76
|
+
# # handle error
|
77
|
+
# end
|
78
|
+
def create(params)
|
79
|
+
result = self.class::Model.create(db_params(params))
|
80
|
+
build_entity(result.to_hash.merge(handle_non_db_params(params)))
|
81
|
+
end
|
82
|
+
|
83
|
+
# Creates an instance of the entity associated with this repository.
|
84
|
+
# Override if any special logic is required to create the entity.
|
85
|
+
#
|
86
|
+
# @param params [Hash]
|
87
|
+
# @return [Object] an instance of `#entity_class`
|
88
|
+
def build_entity(params)
|
89
|
+
add_non_db_entities(params)
|
90
|
+
entity_class.new(params)
|
91
|
+
end
|
92
|
+
|
93
|
+
def db_params(params)
|
94
|
+
params.slice(*self.class::Model.columns)
|
95
|
+
end
|
96
|
+
|
97
|
+
def non_db_params(params)
|
98
|
+
params.reject { |key, _value| self.class::Model.columns.include? key }
|
99
|
+
end
|
100
|
+
|
101
|
+
def handle_non_db_params(params)
|
102
|
+
non_db_params(params)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Inferno
|
2
|
+
module Repositories
|
3
|
+
class Requests < Repository
|
4
|
+
include Import[headers_repo: 'repositories.headers']
|
5
|
+
|
6
|
+
def create(params)
|
7
|
+
request = self.class::Model.create(db_params(params))
|
8
|
+
|
9
|
+
request_headers = (params[:request_headers] || []).map do |header|
|
10
|
+
headers_repo.create(header.merge(request_id: request.index, type: 'request'))
|
11
|
+
end
|
12
|
+
response_headers = (params[:response_headers] || []).map do |header|
|
13
|
+
headers_repo.create(header.merge(request_id: request.index, type: 'response'))
|
14
|
+
end
|
15
|
+
|
16
|
+
headers = request_headers + response_headers
|
17
|
+
|
18
|
+
build_entity(
|
19
|
+
request.to_hash
|
20
|
+
.merge(headers: headers)
|
21
|
+
.merge(non_db_params(params))
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find(id)
|
26
|
+
result =
|
27
|
+
self.class::Model
|
28
|
+
.where(id: id)
|
29
|
+
.select(*entity_class::SUMMARY_FIELDS)
|
30
|
+
.to_a
|
31
|
+
return nil if result.blank?
|
32
|
+
|
33
|
+
build_entity(result.first.to_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_full_request(id)
|
37
|
+
result =
|
38
|
+
self.class::Model
|
39
|
+
.find(id: id)
|
40
|
+
.to_json_data(json_serializer_options)
|
41
|
+
.deep_symbolize_keys!
|
42
|
+
|
43
|
+
build_entity(result)
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_named_request(test_session_id, name)
|
47
|
+
results =
|
48
|
+
self.class::Model
|
49
|
+
.where(test_session_id: test_session_id, name: name.to_s)
|
50
|
+
.map { |model| model.to_json_data(json_serializer_options) }
|
51
|
+
return nil if results.blank?
|
52
|
+
|
53
|
+
result = results.reduce { |max, current| current['index'] > max['index'] ? current : max }
|
54
|
+
result.deep_symbolize_keys!
|
55
|
+
|
56
|
+
build_entity(result)
|
57
|
+
end
|
58
|
+
|
59
|
+
def requests_for_result(result_id)
|
60
|
+
self.class::Model
|
61
|
+
.order(:index)
|
62
|
+
.where(result_id: result_id)
|
63
|
+
.select(*entity_class::SUMMARY_FIELDS)
|
64
|
+
.to_a
|
65
|
+
.map(&:to_hash)
|
66
|
+
.map! { |result| build_entity(result) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def json_serializer_options
|
70
|
+
{
|
71
|
+
include: :headers
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
class Model < Sequel::Model(db)
|
76
|
+
many_to_one :result, class: 'Inferno::Repositories::Results::Model', key: :result_id
|
77
|
+
one_to_many :headers, class: 'Inferno::Repositories::Headers::Model', key: :request_id
|
78
|
+
|
79
|
+
def before_create
|
80
|
+
self.id = SecureRandom.uuid
|
81
|
+
time = Time.now
|
82
|
+
self.created_at ||= time
|
83
|
+
self.updated_at ||= time
|
84
|
+
super
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative 'validate_runnable_reference'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module Repositories
|
5
|
+
class Results < Repository
|
6
|
+
include Import[
|
7
|
+
messages_repo: 'repositories.messages',
|
8
|
+
requests_repo: 'repositories.requests',
|
9
|
+
tests_repo: 'repositories.tests',
|
10
|
+
groups_repo: 'repositories.test_groups',
|
11
|
+
suites_repo: 'repositories.test_suites'
|
12
|
+
]
|
13
|
+
|
14
|
+
def create(params)
|
15
|
+
messages = params.delete(:messages) || []
|
16
|
+
requests = params.delete(:requests) || []
|
17
|
+
super(params).tap do |result|
|
18
|
+
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
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_entity(params)
|
24
|
+
runnable =
|
25
|
+
if params[:test_id]
|
26
|
+
{ test: tests_repo.find(params[:test_id]) }
|
27
|
+
elsif params[:test_group_id]
|
28
|
+
{ test_group: groups_repo.find(params[:test_group_id]) }
|
29
|
+
elsif params[:test_suite_id]
|
30
|
+
{ test_suite: suites_repo.find(params[:test_suite_id]) }
|
31
|
+
else
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
entity_class.new(params.merge(runnable))
|
35
|
+
end
|
36
|
+
|
37
|
+
def json_serializer_options
|
38
|
+
{
|
39
|
+
include: {
|
40
|
+
messages: {},
|
41
|
+
requests: {
|
42
|
+
include: { headers: {} },
|
43
|
+
only: Entities::Request::SUMMARY_FIELDS
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
class Model < Sequel::Model(db)
|
50
|
+
include ValidateRunnableReference
|
51
|
+
|
52
|
+
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
|
54
|
+
many_to_one :test_run, class: 'Inferno::Repositories::TestRuns::Model', key: :test_run_id
|
55
|
+
many_to_one :test_session, class: 'Inferno::Repositories::TestSessions::Model', key: :test_session_id
|
56
|
+
|
57
|
+
def before_create
|
58
|
+
self.id = SecureRandom.uuid
|
59
|
+
time = Time.now
|
60
|
+
self.created_at ||= time
|
61
|
+
self.updated_at ||= time
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate
|
66
|
+
super
|
67
|
+
errors.add(:result, "'#{result}' is not valid") unless Entities::Result::RESULT_OPTIONS.include?(result)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative 'validate_runnable_reference'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module Repositories
|
5
|
+
class TestRuns < Repository
|
6
|
+
include Import[results_repo: 'repositories.results']
|
7
|
+
|
8
|
+
def json_serializer_options
|
9
|
+
{
|
10
|
+
include: {
|
11
|
+
results: results_repo.json_serializer_options
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def results_for_test_run(test_run_id)
|
17
|
+
test_run_hash =
|
18
|
+
self.class::Model
|
19
|
+
.find(id: test_run_id)
|
20
|
+
.to_json_data(json_serializer_options)
|
21
|
+
.deep_symbolize_keys!
|
22
|
+
|
23
|
+
test_run_hash[:results]
|
24
|
+
.map! { |result| results_repo.build_entity(result) }
|
25
|
+
end
|
26
|
+
|
27
|
+
class Model < Sequel::Model(db)
|
28
|
+
include ValidateRunnableReference
|
29
|
+
|
30
|
+
one_to_many :results,
|
31
|
+
eager: [:messages, :requests],
|
32
|
+
class: 'Inferno::Repositories::Results::Model',
|
33
|
+
key: :test_run_id
|
34
|
+
many_to_one :test_session, class: 'Inferno::Repositories::TestSessions::Model', key: :test_session_id
|
35
|
+
|
36
|
+
def before_create
|
37
|
+
self.id = SecureRandom.uuid
|
38
|
+
time = Time.now
|
39
|
+
self.created_at ||= time
|
40
|
+
self.updated_at ||= time
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative 'repository'
|
2
|
+
|
3
|
+
module Inferno
|
4
|
+
module Repositories
|
5
|
+
# Repository that deals with persistence for the `TestSession` entity.
|
6
|
+
class TestSessions < Repository
|
7
|
+
include Import[results_repo: 'repositories.results']
|
8
|
+
|
9
|
+
def json_serializer_options
|
10
|
+
{
|
11
|
+
include: {
|
12
|
+
results: results_repo.json_serializer_options,
|
13
|
+
test_runs: {}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def results_for_test_session(test_session_id)
|
19
|
+
test_session_hash =
|
20
|
+
self.class::Model
|
21
|
+
.find(id: test_session_id)
|
22
|
+
.to_json_data(json_serializer_options)
|
23
|
+
.deep_symbolize_keys!
|
24
|
+
|
25
|
+
test_session_hash[:results]
|
26
|
+
.map! { |result| results_repo.build_entity(result) }
|
27
|
+
end
|
28
|
+
|
29
|
+
class Model < Sequel::Model(db)
|
30
|
+
include Import[test_suites_repo: 'repositories.test_suites']
|
31
|
+
|
32
|
+
one_to_many :results,
|
33
|
+
eager: [:messages, :requests],
|
34
|
+
class: 'Inferno::Repositories::Results::Model',
|
35
|
+
key: :test_session_id
|
36
|
+
one_to_many :test_runs, class: 'Inferno::Repositories::TestRuns::Model', key: :test_session_id
|
37
|
+
|
38
|
+
def before_create
|
39
|
+
self.id = SecureRandom.uuid
|
40
|
+
time = Time.now
|
41
|
+
self.created_at ||= time
|
42
|
+
self.updated_at ||= time
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate
|
47
|
+
super
|
48
|
+
errors.add(:test_suite_id, 'cannot be empty') if test_suite_id.blank?
|
49
|
+
unless test_suites_repo.exists? test_suite_id # rubocop:disable Style/GuardClause
|
50
|
+
errors.add(:test_suite_id, "'#{test_suite_id}' is not valid")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|