inferno_core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/bin/inferno-console +8 -0
  4. data/lib/inferno.rb +15 -0
  5. data/lib/inferno/apps/web/application.rb +12 -0
  6. data/lib/inferno/apps/web/controllers/controller.rb +34 -0
  7. data/lib/inferno/apps/web/controllers/requests/show.rb +16 -0
  8. data/lib/inferno/apps/web/controllers/test_runs/create.rb +39 -0
  9. data/lib/inferno/apps/web/controllers/test_runs/results/index.rb +18 -0
  10. data/lib/inferno/apps/web/controllers/test_runs/show.rb +16 -0
  11. data/lib/inferno/apps/web/controllers/test_sessions/create.rb +26 -0
  12. data/lib/inferno/apps/web/controllers/test_sessions/results/index.rb +17 -0
  13. data/lib/inferno/apps/web/controllers/test_sessions/show.rb +16 -0
  14. data/lib/inferno/apps/web/controllers/test_suites/index.rb +13 -0
  15. data/lib/inferno/apps/web/controllers/test_suites/show.rb +16 -0
  16. data/lib/inferno/apps/web/router.rb +27 -0
  17. data/lib/inferno/apps/web/serializers/header.rb +12 -0
  18. data/lib/inferno/apps/web/serializers/input.rb +16 -0
  19. data/lib/inferno/apps/web/serializers/message.rb +10 -0
  20. data/lib/inferno/apps/web/serializers/request.rb +26 -0
  21. data/lib/inferno/apps/web/serializers/result.rb +21 -0
  22. data/lib/inferno/apps/web/serializers/serializer.rb +16 -0
  23. data/lib/inferno/apps/web/serializers/test.rb +17 -0
  24. data/lib/inferno/apps/web/serializers/test_group.rb +23 -0
  25. data/lib/inferno/apps/web/serializers/test_run.rb +19 -0
  26. data/lib/inferno/apps/web/serializers/test_session.rb +17 -0
  27. data/lib/inferno/apps/web/serializers/test_suite.rb +18 -0
  28. data/lib/inferno/config/application.rb +22 -0
  29. data/lib/inferno/config/boot.rb +5 -0
  30. data/lib/inferno/config/boot/db.rb +23 -0
  31. data/lib/inferno/config/boot/logging.rb +16 -0
  32. data/lib/inferno/config/boot/suites.rb +27 -0
  33. data/lib/inferno/config/boot/web.rb +17 -0
  34. data/lib/inferno/db/migrations/001_create_initial_structure.rb +165 -0
  35. data/lib/inferno/dsl.rb +35 -0
  36. data/lib/inferno/dsl/assertions.rb +93 -0
  37. data/lib/inferno/dsl/fhir_client.rb +152 -0
  38. data/lib/inferno/dsl/fhir_client_builder.rb +56 -0
  39. data/lib/inferno/dsl/fhir_manipulation.rb +25 -0
  40. data/lib/inferno/dsl/fhir_validation.rb +111 -0
  41. data/lib/inferno/dsl/http_client.rb +122 -0
  42. data/lib/inferno/dsl/http_client_builder.rb +54 -0
  43. data/lib/inferno/dsl/request_storage.rb +101 -0
  44. data/lib/inferno/dsl/results.rb +54 -0
  45. data/lib/inferno/dsl/runnable.rb +250 -0
  46. data/lib/inferno/entities.rb +19 -0
  47. data/lib/inferno/entities/attributes.rb +9 -0
  48. data/lib/inferno/entities/entity.rb +15 -0
  49. data/lib/inferno/entities/header.rb +42 -0
  50. data/lib/inferno/entities/message.rb +22 -0
  51. data/lib/inferno/entities/request.rb +166 -0
  52. data/lib/inferno/entities/result.rb +49 -0
  53. data/lib/inferno/entities/test.rb +173 -0
  54. data/lib/inferno/entities/test_group.rb +87 -0
  55. data/lib/inferno/entities/test_input.rb +20 -0
  56. data/lib/inferno/entities/test_run.rb +63 -0
  57. data/lib/inferno/entities/test_session.rb +26 -0
  58. data/lib/inferno/entities/test_suite.rb +73 -0
  59. data/lib/inferno/exceptions.rb +42 -0
  60. data/lib/inferno/public/217.bundle.js +1 -0
  61. data/lib/inferno/public/assets.json +6 -0
  62. data/lib/inferno/public/bundle.js +2 -0
  63. data/lib/inferno/public/bundle.js.LICENSE.txt +65 -0
  64. data/lib/inferno/public/e09b16f5cb645eb05f90c8f38f3409fb.png +0 -0
  65. data/lib/inferno/public/favicon.ico +0 -0
  66. data/lib/inferno/public/logo192.png +0 -0
  67. data/lib/inferno/public/logo512.png +0 -0
  68. data/lib/inferno/repositories.rb +27 -0
  69. data/lib/inferno/repositories/headers.rb +22 -0
  70. data/lib/inferno/repositories/in_memory_repository.rb +41 -0
  71. data/lib/inferno/repositories/messages.rb +35 -0
  72. data/lib/inferno/repositories/repository.rb +106 -0
  73. data/lib/inferno/repositories/requests.rb +89 -0
  74. data/lib/inferno/repositories/results.rb +72 -0
  75. data/lib/inferno/repositories/test_groups.rb +9 -0
  76. data/lib/inferno/repositories/test_runs.rb +46 -0
  77. data/lib/inferno/repositories/test_sessions.rb +56 -0
  78. data/lib/inferno/repositories/test_suites.rb +9 -0
  79. data/lib/inferno/repositories/tests.rb +9 -0
  80. data/lib/inferno/repositories/validate_runnable_reference.rb +42 -0
  81. data/lib/inferno/spec_support.rb +9 -0
  82. data/lib/inferno/test_runner.rb +81 -0
  83. data/lib/inferno/utils/middleware/request_logger.rb +55 -0
  84. data/lib/inferno/version.rb +3 -0
  85. data/spec/support/factory_bot.rb +21 -0
  86. metadata +514 -0
@@ -0,0 +1,13 @@
1
+ module Inferno
2
+ module Web
3
+ module Controllers
4
+ module TestSuites
5
+ class Index < Controller
6
+ def call(_params)
7
+ self.body = serialize(repo.all, view: :summary)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module Inferno
2
+ module Web
3
+ module Controllers
4
+ module TestSuites
5
+ class Show < Controller
6
+ def call(params)
7
+ test_suite = repo.find(params[:id])
8
+ halt 404 if test_suite.nil?
9
+
10
+ self.body = serialize(test_suite, view: :full)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ require 'erb'
2
+
3
+ module Inferno
4
+ module Web
5
+ client_page = ERB.new(File.read(File.join(Inferno::Application.root, 'lib', 'inferno', 'apps', 'web',
6
+ 'index.html.erb'))).result
7
+
8
+ Router = Hanami::Router.new(namespace: Inferno::Web::Controllers) do
9
+ namespace 'api' do
10
+ resources 'test_runs', only: [:create, :show] do
11
+ resources 'results', only: [:index]
12
+ end
13
+
14
+ resources 'test_sessions', only: [:create, :show] do
15
+ resources 'results', only: [:index]
16
+ end
17
+
18
+ resources 'test_suites', only: [:index, :show]
19
+
20
+ resources 'requests', only: [:show]
21
+ end
22
+
23
+ get '/', to: ->(_env) { [200, {}, [client_page]] }
24
+ get '/test_sessions/:id', to: ->(_env) { [200, {}, [client_page]] }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,12 @@
1
+ require_relative 'serializer'
2
+
3
+ module Inferno
4
+ module Web
5
+ module Serializers
6
+ class Header < Serializer
7
+ field :name
8
+ field :value
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ require_relative 'serializer'
2
+
3
+ module Inferno
4
+ module Web
5
+ module Serializers
6
+ class Input < Serializer
7
+ identifier :name
8
+
9
+ field :label, if: :field_present?
10
+ field :description, if: :field_present?
11
+ field :required, if: :field_present?
12
+ field :value, if: :field_present?
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class Message < Serializer
5
+ field :type
6
+ field :message
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class Request < Serializer
5
+ view :summary do
6
+ field :id
7
+ field :created_at, name: :timestamp
8
+ field :verb
9
+ field :url
10
+ field :direction
11
+ field :status
12
+ end
13
+
14
+ view :full do
15
+ include_view :summary
16
+
17
+ field :created_at, name: :timestamp
18
+ association :request_headers, blueprint: Header
19
+ association :response_headers, blueprint: Header
20
+ field :request_body
21
+ field :response_body
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class Result < Serializer
5
+ identifier :id
6
+
7
+ field :test_id, if: :field_present?
8
+ field :test_group_id, if: :field_present?
9
+ field :test_suite_id, if: :field_present?
10
+
11
+ field :test_run_id
12
+ field :test_session_id
13
+ field :result
14
+ field :result_message, if: :field_present?
15
+
16
+ association :messages, blueprint: Message, if: :field_present?
17
+ association :requests, blueprint: Request, view: :summary, if: :field_present?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class Serializer < Blueprinter::Base
5
+ def self.field_present?(field_name, result, options)
6
+ name = options[:name] || field_name
7
+ if result.respond_to?(:[])
8
+ result[name].present?
9
+ else
10
+ result.send(name).present?
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class Test < Serializer
5
+ identifier :id
6
+ field :title
7
+ field :inputs do |test, _options|
8
+ test.inputs.map { |input| { name: input } }
9
+ end
10
+ field :outputs do |test, _options|
11
+ test.outputs.map { |output| { name: output } }
12
+ end
13
+ field :description
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class TestGroup < Serializer
5
+ identifier :id
6
+
7
+ # TODO: fill out test group
8
+ field :title
9
+ field :description
10
+ # field :run_as_group
11
+
12
+ association :groups, name: :test_groups, blueprint: TestGroup
13
+ association :tests, blueprint: Test
14
+ field :inputs do |group, _options|
15
+ group.inputs.map { |input| { name: input } }
16
+ end
17
+ field :outputs do |group, _options|
18
+ group.outputs.map { |input| { name: input } }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class TestRun < Serializer
5
+ identifier :id
6
+ field :test_session_id
7
+
8
+ field :status
9
+
10
+ field :test_group_id, if: :field_present?
11
+ field :test_suite_id, if: :field_present?
12
+ field :test_id, if: :field_present?
13
+
14
+ association :results, blueprint: Result
15
+ association :inputs, blueprint: Input
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'test_suite'
2
+
3
+ module Inferno
4
+ module Web
5
+ module Serializers
6
+ class TestSession < Serializer
7
+ identifier :id
8
+
9
+ field :test_suite_id
10
+
11
+ association :test_suite, blueprint: TestSuite, view: :full
12
+ # association :test_run, blueprint: TestRun
13
+ # association :results, blueprint: Result
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module Inferno
2
+ module Web
3
+ module Serializers
4
+ class TestSuite < Serializer
5
+ view :summary do
6
+ identifier :id
7
+ field :title
8
+ field :description
9
+ end
10
+
11
+ view :full do
12
+ include_view :summary
13
+ association :groups, name: :test_groups, blueprint: TestGroup
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'boot'
2
+
3
+ module Inferno
4
+ class Application < Dry::System::Container
5
+ ::Inferno::Import = injector
6
+
7
+ use :env, inferrer: -> { ENV.fetch('APP_ENV', :development).to_sym }
8
+
9
+ configure do |config|
10
+ config.root = File.expand_path('../../..', __dir__)
11
+ config.default_namespace = 'inferno'
12
+ config.system_dir = File.join('lib', 'inferno', 'config')
13
+ config.bootable_dirs = [File.join('lib', 'inferno', 'config', 'boot')]
14
+
15
+ config.auto_register = 'lib'
16
+ end
17
+
18
+ Application.register('js_host', ENV.fetch('JS_HOST', ''))
19
+
20
+ load_paths!('lib')
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ ENV['APP_ENV'] ||= 'development'
2
+
3
+ root_path = Dir.pwd
4
+
5
+ Dotenv.load(File.join(root_path, '.env'), File.join(root_path, ".env.#{ENV['APP_ENV']}"))
@@ -0,0 +1,23 @@
1
+ Inferno::Application.boot(:db) do
2
+ init do
3
+ use :logging
4
+
5
+ require 'yaml'
6
+
7
+ Sequel::Model.plugin :json_serializer
8
+
9
+ config_path = File.expand_path('database.yml', File.join(Dir.pwd, 'config'))
10
+ config = YAML.load_file(config_path)[ENV['APP_ENV']]
11
+ .merge(logger: Inferno::Application['logger'])
12
+ connection = Sequel.connect(config)
13
+
14
+ register('db.config', config)
15
+ register('db.connection', connection)
16
+ end
17
+
18
+ start do
19
+ Sequel.extension :migration
20
+ migration_path = File.join(Inferno::Application.root, 'lib', 'inferno', 'db', 'migrations')
21
+ Sequel::Migrator.run(Inferno::Application['db.connection'], migration_path)
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ Inferno::Application.boot(:logging) do
2
+ init do
3
+ logger =
4
+ if Inferno::Application.env == :test
5
+ log_file_directory = File.join(Dir.pwd, 'tmp')
6
+ FileUtils.mkdir_p(log_file_directory)
7
+ log_file_path = File.join(log_file_directory, 'test.log')
8
+ log_file = File.open(log_file_path, File::WRONLY | File::APPEND | File::CREAT)
9
+ Logger.new(log_file)
10
+ else
11
+ Logger.new($stdout)
12
+ end
13
+
14
+ register('logger', logger)
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ Inferno::Application.boot(:suites) do
2
+ init do
3
+ use :logging
4
+
5
+ files_to_load = Dir.glob(File.join(Dir.pwd, 'lib', '*.rb'))
6
+
7
+ if ENV['LOAD_DEV_SUITES'] == 'true'
8
+ files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'dev_suites', '**', '*.rb'))
9
+ end
10
+
11
+ if ENV['LOAD_UI_SUITES'] == 'true'
12
+ files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'ui_suites', '**', '*.rb'))
13
+ end
14
+
15
+ if ENV['APP_ENV'] == 'test'
16
+ files_to_load.concat Dir.glob(File.join(Inferno::Application.root, 'spec', 'fixtures', '**', '*.rb'))
17
+ end
18
+
19
+ files_to_load.map! { |path| File.realpath(path) }
20
+
21
+ files_to_load.each do |path|
22
+ require_relative path
23
+ end
24
+
25
+ ObjectSpace.each_object(TracePoint, &:disable)
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ Inferno::Application.boot(:web) do |_app|
2
+ init do
3
+ require 'blueprinter'
4
+ require 'hanami-router'
5
+ require 'hanami-controller'
6
+ require 'oj'
7
+
8
+ Hanami::Controller.configure do
9
+ default_request_format :json
10
+ default_response_format :json
11
+ end
12
+
13
+ Blueprinter.configure do |config|
14
+ config.generator = Oj
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,165 @@
1
+ Sequel.migration do
2
+ change do
3
+ #
4
+ # NOT NEEDED BECUASE THEY ARE DEFINED WITHIN TEST SUITE.
5
+ # MUST BE REFERENCED USING SOME KIND OF GLOBALLY UNIQUE KEY
6
+ # THAT IS REPRESENTED AS A STRING
7
+ #
8
+
9
+ # create_table :test_suites do
10
+ # end
11
+
12
+ # create_table :test_groups do
13
+ # end
14
+
15
+ # create_table :tests do
16
+ # end
17
+
18
+ # create_table :test_inputs do
19
+ # end
20
+
21
+ # create_table :test_outputs do
22
+ # end
23
+
24
+ # A way for the test to signal that it requires some kind of action by the
25
+ # app that is invoking the test (e.g. SMART Launch, perhaps mid-test manual verification)
26
+ # create_table :test_prompts do
27
+ # end
28
+
29
+ # For a given prompt, the tests specify what fields are associated (e.g redirect uri),
30
+ # Those get filled out and stored within the run
31
+ # create_table :test_prompt_field do
32
+ # end
33
+
34
+ create_table :test_sessions do
35
+ column :id, String, primary_key: true, null: false
36
+ column :test_suite_id, String
37
+
38
+ column :created_at, DateTime, null: false
39
+ column :updated_at, DateTime, null: false
40
+ end
41
+
42
+ create_table :test_runs do
43
+ column :id, String, primary_key: true, null: false
44
+ column :status, String
45
+ foreign_key :test_session_id, :test_sessions, index: true, type: String
46
+ index [:test_session_id, :status] # Searching by unfinished test runs seems like it will be a likely query
47
+
48
+ column :test_suite_id, String, index: true
49
+ column :test_group_id, String, index: true
50
+ column :test_id, String, index: true
51
+
52
+ column :created_at, DateTime, null: false
53
+ column :updated_at, DateTime, null: false
54
+ end
55
+
56
+ create_table :test_run_inputs do
57
+ column :id, String, primary_key: true, null: false
58
+ foreign_key :test_run_id, :test_runs, index: true, type: String
59
+ column :test_input_id, String
60
+ column :value, String
61
+
62
+ column :created_at, DateTime, null: false
63
+ column :updated_at, DateTime, null: false
64
+ end
65
+
66
+ create_table :results do
67
+ column :id, String, primary_key: true, null: false
68
+
69
+ foreign_key :test_run_id, :test_runs, index: true, type: String
70
+ foreign_key :test_session_id, :test_sessions, index: true, type: String
71
+
72
+ column :result, String
73
+ column :result_message, String
74
+
75
+ column :test_suite_id, String
76
+ column :test_group_id, String
77
+ column :test_id, String
78
+
79
+ column :created_at, DateTime, null: false
80
+ column :updated_at, DateTime, null: false
81
+ end
82
+
83
+ create_table :result_inputs do
84
+ column :id, String, primary_key: true, null: false
85
+ foreign_key :result_id, :results, index: true, type: String
86
+ column :test_input_id, String
87
+ column :value, String
88
+
89
+ column :created_at, DateTime, null: false
90
+ column :updated_at, DateTime, null: false
91
+ end
92
+
93
+ create_table :result_outputs do
94
+ column :id, String, primary_key: true, null: false
95
+ foreign_key :result_id, :results, index: true, type: String
96
+ column :test_output_id, String
97
+ column :value, String
98
+
99
+ column :created_at, DateTime, null: false
100
+ column :updated_at, DateTime, null: false
101
+ end
102
+
103
+ create_table :result_prompt_values do
104
+ column :id, String, primary_key: true, null: false
105
+
106
+ foreign_key :result_id, :results, index: true, type: String
107
+
108
+ column :test_prompt_id, String, null: false
109
+ column :value, String, null: false
110
+
111
+ column :created_at, DateTime, null: false
112
+ column :updated_at, DateTime, null: false
113
+ end
114
+
115
+ create_table :messages do
116
+ primary_key :index
117
+ column :id, String, index: true, null: false
118
+ foreign_key :result_id, :results, index: true, type: String
119
+ column :type, String
120
+ column :message, String
121
+
122
+ column :created_at, DateTime, null: false
123
+ column :updated_at, DateTime, null: false
124
+ end
125
+
126
+ create_table :requests do
127
+ primary_key :index
128
+ column :id, String, index: true, null: false
129
+ column :verb, String
130
+ column :url, String
131
+ column :direction, String
132
+ column :status, Integer
133
+ column :name, String
134
+ column :request_body, String, text: true
135
+ column :response_body, String, text: true # It would be nice if we could store this on disk
136
+
137
+ # Requires requests to be a part of tests now.
138
+ foreign_key :result_id, :results, index: true, type: String
139
+ foreign_key :test_session_id, :test_sessions, index: true, type: String
140
+ add_index [:test_session_id, :name], concurrently: true
141
+
142
+ column :created_at, DateTime, null: false
143
+ column :updated_at, DateTime, null: false
144
+ end
145
+
146
+ create_table :headers do
147
+ column :id, String, index: true, null: false
148
+ foreign_key :request_id, :requests, index: true, type: String
149
+ column :type, String # request / response
150
+ column :name, String
151
+ column :value, String
152
+
153
+ column :created_at, DateTime, null: false
154
+ column :updated_at, DateTime, null: false
155
+ end
156
+
157
+ create_table :session_data do
158
+ column :id, String, index: true, null: false
159
+ foreign_key :test_session_id, :test_sessions, index: true, type: String
160
+ column :name, String
161
+ column :value, String
162
+ index [:test_session_id, :name]
163
+ end
164
+ end
165
+ end