Class: DaVinciPlanNetTestKit::Generator::GroupGenerator
- Inherits:
-
Object
- Object
- DaVinciPlanNetTestKit::Generator::GroupGenerator
- Defined in:
- lib/davinci_plan_net_test_kit/generator/group_generator.rb
Instance Attribute Summary collapse
-
#base_output_dir ⇒ Object
Returns the value of attribute base_output_dir.
-
#group_metadata ⇒ Object
Returns the value of attribute group_metadata.
Class Method Summary collapse
Instance Method Summary collapse
- #add_special_tests ⇒ Object
- #any_chain_requirements? ⇒ Boolean
- #base_metadata_file_name ⇒ Object
- #base_output_file_name ⇒ Object
- #chain_requirement_list_for_param(search_parameter) ⇒ Object
- #chainable_parameters ⇒ Object
- #class_name ⇒ Object
- #description ⇒ Object
- #forward_chain_description ⇒ Object
- #forward_chain_table ⇒ Object
- #generate ⇒ Object
- #group_id ⇒ Object
- #include_description ⇒ Object
- #include_param_name_string ⇒ Object
-
#initialize(group_metadata, base_output_dir) ⇒ GroupGenerator
constructor
A new instance of GroupGenerator.
- #metadata_file_name ⇒ Object
- #module_name ⇒ Object
- #optional? ⇒ Boolean
- #output ⇒ Object
- #output_file_name ⇒ Object
- #profile_identifier ⇒ Object
- #profile_name ⇒ Object
- #profile_url ⇒ Object
- #required_searches ⇒ Object
- #resource_type ⇒ Object
- #reverse_chain_description ⇒ Object
- #reverse_chain_string ⇒ Object
- #revinclude_description ⇒ Object
- #revinclude_param_name_string ⇒ Object
- #search_description ⇒ Object
- #search_param_name_string ⇒ Object
- #search_validation_resource_type ⇒ Object
- #short_description ⇒ Object
- #template ⇒ Object
- #test_file_list ⇒ Object
- #test_id_list ⇒ Object
- #title ⇒ Object
Constructor Details
#initialize(group_metadata, base_output_dir) ⇒ GroupGenerator
Returns a new instance of GroupGenerator.
17 18 19 20 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 17 def initialize(, base_output_dir) self. = self.base_output_dir = base_output_dir end |
Instance Attribute Details
#base_output_dir ⇒ Object
Returns the value of attribute base_output_dir.
15 16 17 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 15 def base_output_dir @base_output_dir end |
#group_metadata ⇒ Object
Returns the value of attribute group_metadata.
15 16 17 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 15 def @group_metadata end |
Class Method Details
.generate(ig_metadata, base_output_dir) ⇒ Object
8 9 10 11 12 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 8 def generate(, base_output_dir) .ordered_groups .reject { |group| SpecialCases.exclude_group? group } .each { |group| new(group, base_output_dir).generate } end |
Instance Method Details
#add_special_tests ⇒ Object
116 117 118 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 116 def add_special_tests return if .reformatted_version == 'v311' end |
#any_chain_requirements? ⇒ Boolean
96 97 98 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 96 def any_chain_requirements? !chainable_parameters.empty? end |
#base_metadata_file_name ⇒ Object
34 35 36 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 34 def "metadata.yml" end |
#base_output_file_name ⇒ Object
30 31 32 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 30 def base_output_file_name "#{class_name.underscore}.rb" end |
#chain_requirement_list_for_param(search_parameter) ⇒ Object
90 91 92 93 94 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 90 def chain_requirement_list_for_param(search_parameter) sym = search_parameter.class != Symbol ? search_parameter.to_sym : search_parameter req_list = .search_definitions[sym][:chain].nil? ? [] : .search_definitions[sym][:chain] req_list end |
#chainable_parameters ⇒ Object
100 101 102 103 104 105 106 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 100 def chainable_parameters chainable_params = .search_definitions.keys.reject do |search_parameter| req_list = chain_requirement_list_for_param(search_parameter) req_list.nil? || req_list.empty? end chainable_params end |
#class_name ⇒ Object
38 39 40 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 38 def class_name "#{Naming.upper_camel_case_for_profile()}Group" end |
#description ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 309 def description <<~DESCRIPTION # Background The #{title} sequence verifies that the system under test is able to provide correct responses for #{resource_type} queries. These queries must return resources conforming to the #{profile_name} profile as specified in the Plan Net #{.version} Implementation Guide. # Testing Methodology ## Instance Gathering Inferno will first identify and obtain a set of instances to use for the rest of the tests, requiring at least one instance to be identified for the test to pass. Instances to gather are indentified in two ways. One or both will be used, depending on user input. ### Parameterless searches Instances can be gathered using a query requesting all instances of #{resource_type} (e.g., `GET [FHIR Endpoint]/#{resource_type}`). #{SpecialCases.has_parameterless_filter?(profile_name) ? SpecialCases.parameterless_filter_description(profile_name) : "" } Gathering through this method is controlled by the following inputs (used for all profiles): - "Use parameterless searches to identify instances?": parameterless searches can be disabled using this input if, for example, the server under test does not support them, or not all instances on the server should be expected to conform to Plan Net profiles. In this case the user **MUST** provide specific instance ids to gather. - "Maximum number of instances to gather using parameterless searches": sets an upper bound on the number of instances Inferno will gather from parameterless searches. - "Maximum pages of results to consider when using parameterless searches": sets an upper bound on the number of pages of search results Inferno will load when gathering instances using parameterless searches. ### User-provided instance ids If ids are listed in the "ids of #{profile_name} instances" optional input, they will be read and included at the start of the set of gathered instances. #{search_description} #{include_description} #{revinclude_description} #{forward_chain_description} #{reverse_chain_description} ## Profile Validation Each resource identified during instance gathering and other queries run during this test sequence is expected to conform to the [#{profile_name}](#{.versioned_profile_url}). Each element is checked by the HL7 Validator against terminology binding and cardinality requirements. Elements with a required binding are validated against their bound ValueSet. If the code/system in the element is not part of the ValueSet, then the test will fail. ## Must Support Each profile contains elements marked as "must support". This test sequence expects to see each of these elements populated at least once. The test will look through the #{profile_name} instances identified during instance gathering and other queries run during this test sequence. If no populated instance can be found for any must support element, the test will fail. ## Reference Validation At least one instance of each external reference in elements marked as "must support" within the resources provided by the system must resolve. The test will attempt to read each reference found and will fail if no read succeeds. DESCRIPTION end |
#forward_chain_description ⇒ Object
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 253 def forward_chain_description return '' if !any_chain_requirements? <<~FORWARD_CHAINING_DESCRIPTION ## Forward Chaining Requirement Testing This test sequence will perform a search with each required combination of forward chaining search parameters. This sequence will perform searches with the following chaining parameters: #{forward_chain_table} All forward chain searches will look for candidate instances of the resource being chained through from the results of previously run _include tests. Candidates are chosen from previously returned instances that have the chain parameter element filled. Each search test will use one of these values to build the requests for the test. The test will be skipped if no candidates can be found. The test will first create and execute the forward chaining request. The test will then perform a basic search test on the resource being chained through, using the same value in the previous request. Each resource returned in the first request will then be checked, validating that the element being chained through is populated by the id of _any_ of the resources returned by the second request. FORWARD_CHAINING_DESCRIPTION end |
#forward_chain_table ⇒ Object
156 157 158 159 160 161 162 163 164 165 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 156 def forward_chain_table chain_table = "| Search Parameters | Chain Requirements |\n| :---: | :---: |\n" # Iterate through the chain requirements and add to table chainable_parameters.each do |chain_param| chain_requirement_list = chain_requirement_list_for_param(chain_param).map { |chain| chain[:chain]} chain_table += "| #{chain_param} | #{chain_requirement_list.join(', ')} |\n" end chain_table end |
#generate ⇒ Object
108 109 110 111 112 113 114 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 108 def generate # add_special_tests File.open(output_file_name, 'w') { |f| f.write(output) } .id = group_id .file_name = base_output_file_name File.open(, 'w') { |f| f.write(YAML.dump(.to_hash)) } end |
#group_id ⇒ Object
66 67 68 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 66 def group_id "davinci_plan_net_#{.reformatted_version}_#{profile_identifier}" end |
#include_description ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 207 def include_description return '' if .include_params.blank? <<~INCLUDE_DESCRIPTION ## _include Requirement Testing This test sequence will perform a search with each required _include search parameter associated with this profile. This sequence will perform searches with the following includes: #{include_param_name_string} Each _include search will look for a candidate id that has the target reference element populated from the results of instance gathering. Each search will use the identified #{profile_name} id and the include parameter. The returned instances are checked to ensure that any instances of the included type are referenced by returned instances of the searched resource type. INCLUDE_DESCRIPTION end |
#include_param_name_string ⇒ Object
144 145 146 147 148 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 144 def include_param_name_string .include_params .map { |names| "* #{names}" } .join("\n") end |
#metadata_file_name ⇒ Object
58 59 60 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 58 def File.join(base_output_dir, profile_identifier, ) end |
#module_name ⇒ Object
42 43 44 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 42 def module_name "DaVinciPlanNet#{.reformatted_version.upcase}" end |
#optional? ⇒ Boolean
86 87 88 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 86 def optional? false #No Optional groups in Plan Net end |
#output ⇒ Object
26 27 28 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 26 def output @output ||= ERB.new(template).result(binding) end |
#output_file_name ⇒ Object
54 55 56 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 54 def output_file_name File.join(base_output_dir, base_output_file_name) end |
#profile_identifier ⇒ Object
62 63 64 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 62 def profile_identifier Naming.snake_case_for_profile() end |
#profile_name ⇒ Object
78 79 80 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 78 def profile_name .profile_name end |
#profile_url ⇒ Object
82 83 84 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 82 def profile_url .profile_url end |
#required_searches ⇒ Object
133 134 135 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 133 def required_searches .searches.select { |search| search[:expectation] == 'SHALL' } end |
#resource_type ⇒ Object
70 71 72 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 70 def resource_type .resource end |
#reverse_chain_description ⇒ Object
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 277 def reverse_chain_description return '' if !test_id_list.any? {|test_id| test_id.include?('reverse_chain')} <<~REVERSE_CHAINING_DESCRIPTION ## Reverse Chaining Requirement Testing This test sequence will perform a search with each required combination of reverse chaining search parameters, including the following combinations: #{reverse_chain_string} All reverse chain searches will look for candidate instances from the results of previous tests _only_ if tests are ran from the suite level. Candidates are selected by checking they have both the second (reference element) and third (constraining element) elements populated. The search value will be taken from the constraining element on the identified candidate. If running from the profile level, inputs of the form "\'\[constraining element\]\' value from a \[source resource type\] instance with \'\[reference element\]\' populated" are provided for these tests upon test start. Enter a value from the \[constraining element\] element of an instance of a \[source resource type\] resource that also contains a reference to the tested #{resource_type} in its \[reference element\] element. The input will be used as the search value. The test will first create and execute a request with the chain parameter. The test will then perform a search against the \[source resource type\] with the \[constraining\] SeachParameter using the same search value. Each resource returned in the first request will then be checked, validating that the ids of those resources are also referenced by _any_ of the resources returned by the second request in its \[reference element\] element. REVERSE_CHAINING_DESCRIPTION end |
#reverse_chain_string ⇒ Object
167 168 169 170 171 172 173 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 167 def reverse_chain_string # Placeholder until we have a more clear way of inferring reverse requirements examples = File.read('lib/davinci_plan_net_test_kit/custom_groups/reverse_chain_tests/examples.json') examples_hash = JSON.parse(examples)[Naming.upper_camel_case_for_profile()] .map { |test_example| "* #{test_example['source_resource']}:#{test_example['target_param']}:#{test_example['constraining_param']}" } .join("\n") end |
#revinclude_description ⇒ Object
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 227 def revinclude_description return '' if .revincludes.blank? <<~REVINCLUDE_DESCRIPTION ## _revinclude Requirement Testing This test sequence will perform a search with each required _revinclude search parameter associated with this resource. This sequence will perform searches with the following revincludes: #{revinclude_param_name_string} All _revinclude searches will look for candidate ids from the results of instance gathering _only_ if tests are ran from the suite level. Each search will use a #{profile_name} id that is referenced by an instance of the revincluded resource in the element that is the target of the revinclude search parameter. The returned instances are checked to ensure that any instances of the revincluded type reference returned instances of the searched resource type. If running from the group level, inputs of the form "#{resource_type} instance ids referenced in \[referencing profile\].\[referencing element\]" are provided for these tests. Enter ids of the #{resource_type} profile that are referenced by the \[referencing element\] of an instance of the \[referencing profile\]. REVINCLUDE_DESCRIPTION end |
#revinclude_param_name_string ⇒ Object
150 151 152 153 154 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 150 def revinclude_param_name_string .revincludes .map { |names| "* #{names}" } .join("\n") end |
#search_description ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 175 def search_description return '' if required_searches.blank? <<~SEARCH_DESCRIPTION ## Searching This test sequence will perform a search with each required search parameter associated with this resource individually. Searches with the following parameters will be performed: #{search_param_name_string} ### Search Parameters Each search will look for its parameter values from the results of the instance gathering step. For example, for a search using the `identifier` search parameter, the test searches the gathered instances for one with the `identifier` element populated and then uses that value as the queried `identifier` value. If a value cannot be found this way, the search test is skipped for that search parameter. ### Search Validation Inferno will retrieve all bundle pages of the reply for #{search_validation_resource_type}. Each of the returned instances is then checked to see if it matches the searched parameters in accordance with [FHIR search guidelines](https://www.hl7.org/fhir/search.html). The test will fail, for example, if a #{profile_name} search for `#{required_searches.first[:names].first}=X` returns a #{profile_name} instance where `#{required_searches.first[:names].first}!=X` SEARCH_DESCRIPTION end |
#search_param_name_string ⇒ Object
137 138 139 140 141 142 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 137 def search_param_name_string required_searches .map { |search| search[:names].join(' + ') } .map { |names| "* #{names}" } .join("\n") end |
#search_validation_resource_type ⇒ Object
74 75 76 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 74 def search_validation_resource_type "#{resource_type} resources" end |
#short_description ⇒ Object
50 51 52 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 50 def short_description .short_description end |
#template ⇒ Object
22 23 24 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 22 def template @template ||= File.read(File.join(__dir__, 'templates', 'group.rb.erb')) end |
#test_file_list ⇒ Object
125 126 127 128 129 130 131 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 125 def test_file_list @test_file_list ||= .tests.map do |test| name_without_suffix = test[:file_name].delete_suffix('.rb') name_without_suffix.start_with?('..') ? name_without_suffix : "#{profile_identifier}/#{name_without_suffix}" end end |
#test_id_list ⇒ Object
120 121 122 123 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 120 def test_id_list @test_id_list ||= .tests.map { |test| test[:id] } end |
#title ⇒ Object
46 47 48 |
# File 'lib/davinci_plan_net_test_kit/generator/group_generator.rb', line 46 def title .title end |