Module: Inferno::DSL::Runnable
- Includes:
- Utils::MarkdownFormatter
- Included in:
- Entities::TestGroup, Entities::TestSuite
- Defined in:
- lib/inferno/dsl/runnable.rb
Overview
This module contains the DSL for defining child entities in the test definition framework.
Constant Summary collapse
- VARIABLES_NOT_TO_COPY =
Class instance variables are used to hold the metadata for Runnable classes. When inheriting from a Runnable class, these class instance variables need to be copied. Some instance variables should not be copied, and will need to be repopulated from scratch on the new class. Any child Runnable classes will themselves need to be subclassed so that their parent can be updated.
[ :@id, # New runnable will have a different id :@database_id, # New runnable will have a different database_id :@parent, # New runnable unlikely to have the same parent :@all_children, # New subclasses have to be made for each child :@test_count, # Needs to be recalculated :@config, # Needs to be set by calling .config, which does extra work :@available_inputs, # Needs to be recalculated :@children_available_inputs # Needs to be recalculated ].freeze
Instance Attribute Summary collapse
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#suite_option_requirements ⇒ Object
readonly
Returns the value of attribute suite_option_requirements.
Class Method Summary collapse
-
.extended(extending_class) ⇒ Object
When a class (e.g. TestSuite/TestGroup) uses this module, set it up so that subclassing it works correctly.
Instance Method Summary collapse
- #add_self_to_repository ⇒ Object
- #all_children ⇒ Object
- #all_descendants ⇒ Object
- #all_verified_requirements(suite_options = []) ⇒ Object
-
#block(&block) ⇒ Proc
(also: #run)
Set/Get the block that is executed when a runnable is run.
- #child_metadata(metadata = nil) ⇒ Object
- #children(selected_suite_options = []) ⇒ Object
- #configure_child_class(klass, hash_args) ⇒ Object
- #copy_instance_variables(subclass) ⇒ Object
- #create_child_class(hash_args) ⇒ Object
- #database_id ⇒ Object
-
#deep_dup(value) ⇒ Object
Recursively duplicate arrays/hashes to prevent them from being shared across different runnables.
- #default_id ⇒ Object
-
#define_child(*args) ⇒ Object
This method defines a child entity.
-
#description(new_description = nil) ⇒ String
Set/Get a runnable’s description.
- #handle_child_definition_block(klass) ⇒ Object
-
#id(new_id = nil) ⇒ String, Symbol
Set/Get a runnable’s id.
-
#input_instructions(new_input_instructions = nil) ⇒ String
Set/Get a runnable’s input instructions.
- #inspect ⇒ Object
-
#optional(optional = true) ⇒ void
Mark as optional.
-
#optional? ⇒ Boolean
The test or group is optional if true.
- #process_args(args) ⇒ Object
-
#remove(id_to_remove) ⇒ Object
Remove a child test/group.
- #remove_self_from_repository ⇒ Object
-
#reorder(child_id, new_index) ⇒ Object
Move a child test/group to a new position within the children list.
-
#replace(id_to_replace, replacement_id) {|Inferno::TestGroup, Inferno::Test| ... } ⇒ Object
Replace a child test/group.
-
#repository ⇒ Object
An instance of the repository for the class using this module.
-
#required(required = true) ⇒ void
Mark as required.
-
#required? ⇒ Boolean
The test or group is required if true.
-
#required_suite_options(suite_option_requirements) ⇒ void
Set/get suite options required for this runnable to be executed.
-
#resume_test_route(method, path, tags: [], result: 'pass') { ... } ⇒ void
Create a route which will resume a test run when a request is received.
-
#route(method, path, handler) ⇒ void
Create a route to handle a request.
-
#short_description(new_short_description = nil) ⇒ String
Set/Get a runnable’s short one-sentence description.
-
#short_title(new_short_title = nil) ⇒ String
Set/Get a runnable’s short title.
- #suite ⇒ Object
-
#suite_endpoint(method, path, endpoint_class) ⇒ void
Create an endpoint to receive incoming requests during a Test Run.
- #test_count(selected_suite_options = []) ⇒ Object
-
#title(new_title = nil) ⇒ String
Set/Get a runnable’s title.
- #user_runnable? ⇒ Boolean
-
#verifies_requirements(*requirement_ids) ⇒ Array<String>
Set/Get the IDs of requirements verified by this runnable Set with [] to clear the list.
Methods included from Utils::MarkdownFormatter
Instance Attribute Details
#parent ⇒ Object
Returns the value of attribute parent.
12 13 14 |
# File 'lib/inferno/dsl/runnable.rb', line 12 def parent @parent end |
#suite_option_requirements ⇒ Object (readonly)
Returns the value of attribute suite_option_requirements.
13 14 15 |
# File 'lib/inferno/dsl/runnable.rb', line 13 def suite_option_requirements @suite_option_requirements end |
Class Method Details
.extended(extending_class) ⇒ Object
When a class (e.g. TestSuite/TestGroup) uses this module, set it up so that subclassing it works correctly.
-
add the subclass to the relevant repository when it is created
-
copy the class instance variables from the superclass
-
add a hook to the subclass so that its subclasses do the same
23 24 25 26 27 28 29 30 31 |
# File 'lib/inferno/dsl/runnable.rb', line 23 def self.extended(extending_class) super extending_class.extend Configurable extending_class.extend InputOutputHandling extending_class.define_singleton_method(:inherited) do |subclass| copy_instance_variables(subclass) end end |
Instance Method Details
#add_self_to_repository ⇒ Object
81 82 83 |
# File 'lib/inferno/dsl/runnable.rb', line 81 def add_self_to_repository repository.insert(self) end |
#all_children ⇒ Object
330 331 332 |
# File 'lib/inferno/dsl/runnable.rb', line 330 def all_children @all_children ||= [] end |
#all_descendants ⇒ Object
335 336 337 |
# File 'lib/inferno/dsl/runnable.rb', line 335 def all_descendants children.flat_map { |child| [child] + child.all_descendants } end |
#all_verified_requirements(suite_options = []) ⇒ Object
559 560 561 562 563 |
# File 'lib/inferno/dsl/runnable.rb', line 559 def all_verified_requirements( = []) verifies_requirements + children().flat_map do |child| child.all_verified_requirements() end.uniq end |
#block(&block) ⇒ Proc Also known as: run
Set/Get the block that is executed when a runnable is run
321 322 323 324 325 |
# File 'lib/inferno/dsl/runnable.rb', line 321 def block(&block) return @block unless block_given? @block = block end |
#child_metadata(metadata = nil) ⇒ Object
136 137 138 139 |
# File 'lib/inferno/dsl/runnable.rb', line 136 def ( = nil) @child_metadata = if @child_metadata end |
#children(selected_suite_options = []) ⇒ Object
544 545 546 547 548 549 550 551 552 553 554 555 556 |
# File 'lib/inferno/dsl/runnable.rb', line 544 def children( = []) return all_children if .blank? all_children.select do |child| requirements = child.suite_option_requirements if requirements.blank? true else requirements.all? { |requirement| .include? requirement } end end end |
#configure_child_class(klass, hash_args) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/inferno/dsl/runnable.rb', line 155 def configure_child_class(klass, hash_args) # rubocop:disable Metrics/CyclomaticComplexity inputs.each do |name| next if klass.inputs.any? { |klass_input_name| klass_input_name == name } klass.input name end outputs.each do |output_name| next if klass.outputs.include? output_name klass.output output_name end klass.config(config) klass.all_children.select!(&:required?) if hash_args.delete(:exclude_optional) hash_args.each do |key, value| if value.is_a? Array klass.send(key, *value) else klass.send(key, value) end end klass.all_children.each do |child_class| klass.configure_child_class(child_class, {}) child_class.add_self_to_repository end end |
#copy_instance_variables(subclass) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/inferno/dsl/runnable.rb', line 64 def copy_instance_variables(subclass) instance_variables .reject { |variable| VARIABLES_NOT_TO_COPY.include? variable } .each { |variable| subclass.instance_variable_set(variable, deep_dup(instance_variable_get(variable))) } subclass.config(config) new_children = all_children.map do |child| Class.new(child).tap do |subclass_child| subclass_child.parent = subclass end end subclass.instance_variable_set(:@all_children, new_children) end |
#create_child_class(hash_args) ⇒ Object
142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/inferno/dsl/runnable.rb', line 142 def create_child_class(hash_args) superclass_id = hash_args.delete :from return Class.new([:class]) if superclass_id.blank? superclass = [:repo].find(superclass_id) raise Exceptions::ParentNotLoadedException.new([:class], superclass_id) unless superclass Class.new(superclass) end |
#database_id ⇒ Object
210 211 212 |
# File 'lib/inferno/dsl/runnable.rb', line 210 def database_id @database_id ||= id end |
#deep_dup(value) ⇒ Object
Recursively duplicate arrays/hashes to prevent them from being shared across different runnables
53 54 55 56 57 58 59 60 61 |
# File 'lib/inferno/dsl/runnable.rb', line 53 def deep_dup(value) if value.is_a? Array value.map { |element| deep_dup(element) } elsif value.is_a? Hash value.transform_values { |element| deep_dup(element) } else value.dup end end |
#default_id ⇒ Object
313 314 315 |
# File 'lib/inferno/dsl/runnable.rb', line 313 def default_id to_s end |
#define_child(*args) ⇒ Object
This method defines a child entity. Classes using this module should alias the method name they wish to use to define child entities to this method.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/inferno/dsl/runnable.rb', line 101 def define_child(*args, &) hash_args = process_args(args) klass = create_child_class(hash_args) klass.parent = self all_children << klass configure_child_class(klass, hash_args) handle_child_definition_block(klass, &) klass.add_self_to_repository klass end |
#description(new_description = nil) ⇒ String
Set/Get a runnable’s description
238 239 240 241 242 |
# File 'lib/inferno/dsl/runnable.rb', line 238 def description(new_description = nil) return @description if new_description.nil? @description = format_markdown(new_description) end |
#handle_child_definition_block(klass) ⇒ Object
187 188 189 |
# File 'lib/inferno/dsl/runnable.rb', line 187 def handle_child_definition_block(klass, &) klass.class_eval(&) if block_given? end |
#id(new_id = nil) ⇒ String, Symbol
Set/Get a runnable’s id
195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/inferno/dsl/runnable.rb', line 195 def id(new_id = nil) return @id if new_id.nil? && @id.present? prefix = parent ? "#{parent.id}-" : '' @base_id = new_id || @base_id || default_id @id = "#{prefix}#{@base_id}" if @id.length > 255 hash = Digest::SHA1.hexdigest(@id)[0...10] @database_id = "#{@id[0...244]}-#{hash}" end @id end |
#input_instructions(new_input_instructions = nil) ⇒ String
Set/Get a runnable’s input instructions
258 259 260 261 262 |
# File 'lib/inferno/dsl/runnable.rb', line 258 def input_instructions(new_input_instructions = nil) return @input_instructions if new_input_instructions.nil? @input_instructions = format_markdown(new_input_instructions) end |
#inspect ⇒ Object
566 567 568 569 570 571 572 573 574 |
# File 'lib/inferno/dsl/runnable.rb', line 566 def inspect non_dynamic_ancestor = ancestors.find { |ancestor| !ancestor.to_s.start_with? '#' } "#<#{non_dynamic_ancestor}".tap do |inspect_string| inspect_string.concat(" @id=#{id.inspect},") inspect_string.concat(" @short_id=#{short_id.inspect},") if respond_to? :short_id inspect_string.concat(" @title=#{title.inspect}") inspect_string.concat('>') end end |
#optional(optional = true) ⇒ void
This method returns an undefined value.
Mark as optional. Tests are required by default.
283 284 285 |
# File 'lib/inferno/dsl/runnable.rb', line 283 def optional(optional = true) # rubocop:disable Style/OptionalBooleanParameter @optional = optional end |
#optional? ⇒ Boolean
The test or group is optional if true
301 302 303 |
# File 'lib/inferno/dsl/runnable.rb', line 301 def optional? !!@optional end |
#process_args(args) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/inferno/dsl/runnable.rb', line 120 def process_args(args) hash_args = if args[0].is_a? Hash args[0] elsif args[1].is_a? Hash args[1] else {} end hash_args[:title] = args[0] if args[0].is_a? String hash_args end |
#remove(id_to_remove) ⇒ Object
Remove a child test/group
537 538 539 540 541 |
# File 'lib/inferno/dsl/runnable.rb', line 537 def remove(id_to_remove) removed = children.select { |child| child.id.to_s.end_with? id_to_remove.to_s } children.reject! { |child| child.id.to_s.end_with? id_to_remove.to_s } removed.each(&:remove_self_from_repository) end |
#remove_self_from_repository ⇒ Object
86 87 88 89 |
# File 'lib/inferno/dsl/runnable.rb', line 86 def remove_self_from_repository repository.remove(self) children.each(&:remove_self_from_repository) end |
#reorder(child_id, new_index) ⇒ Object
Move a child test/group to a new position within the children list.
485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
# File 'lib/inferno/dsl/runnable.rb', line 485 def reorder(child_id, new_index) index = children.find_index { |child| child.id.to_s.end_with? child_id.to_s } raise Exceptions::RunnableChildNotFoundException.new(child_id, self) unless index unless new_index.between?(0, children.length - 1) Inferno::Application[:logger].error <<~ERROR Error trying to reorder children for #{self}: new_index #{new_index} for #{child_id} is out of range (must be between 0 and #{children.length - 1}) ERROR return end child = children.delete_at(index) children.insert(new_index, child) end |
#replace(id_to_replace, replacement_id) {|Inferno::TestGroup, Inferno::Test| ... } ⇒ Object
Replace a child test/group
514 515 516 517 518 519 520 521 522 523 524 525 526 |
# File 'lib/inferno/dsl/runnable.rb', line 514 def replace(id_to_replace, replacement_id, &) index = children.find_index { |child| child.id.to_s.end_with? id_to_replace.to_s } raise Exceptions::RunnableChildNotFoundException.new(id_to_replace, self) unless index if children[index] < Inferno::TestGroup group(from: replacement_id, &) else test(from: replacement_id, &) end remove(id_to_replace) children.insert(index, children.pop) end |
#repository ⇒ Object
An instance of the repository for the class using this module
93 94 95 |
# File 'lib/inferno/dsl/runnable.rb', line 93 def repository nil end |
#required(required = true) ⇒ void
This method returns an undefined value.
Mark as required
Tests are required by default. This method is provided to make an existing optional test required.
294 295 296 |
# File 'lib/inferno/dsl/runnable.rb', line 294 def required(required = true) # rubocop:disable Style/OptionalBooleanParameter @optional = !required end |
#required? ⇒ Boolean
The test or group is required if true
308 309 310 |
# File 'lib/inferno/dsl/runnable.rb', line 308 def required? !optional? end |
#required_suite_options(suite_option_requirements) ⇒ void
This method returns an undefined value.
Set/get suite options required for this runnable to be executed.
471 472 473 474 475 476 |
# File 'lib/inferno/dsl/runnable.rb', line 471 def (suite_option_requirements) @suite_option_requirements = suite_option_requirements.map do |key, value| DSL::SuiteOption.new(id: key, value:) end end |
#resume_test_route(method, path, tags: [], result: 'pass') { ... } ⇒ void
This method returns an undefined value.
Create a route which will resume a test run when a request is received
382 383 384 385 386 387 388 389 390 |
# File 'lib/inferno/dsl/runnable.rb', line 382 def resume_test_route(method, path, tags: [], result: 'pass', &block) route_class = Class.new(ResumeTestRoute) do |klass| klass.singleton_class.instance_variable_set(:@test_run_identifier_block, block) klass.singleton_class.instance_variable_set(:@tags, ) klass.singleton_class.instance_variable_set(:@result, result) end route(method, path, route_class) end |
#route(method, path, handler) ⇒ void
This method returns an undefined value.
Create a route to handle a request
424 425 426 |
# File 'lib/inferno/dsl/runnable.rb', line 424 def route(method, path, handler) Inferno.routes << { method:, path:, handler:, suite: } end |
#short_description(new_short_description = nil) ⇒ String
Set/Get a runnable’s short one-sentence description
248 249 250 251 252 |
# File 'lib/inferno/dsl/runnable.rb', line 248 def short_description(new_short_description = nil) return @short_description if new_short_description.nil? @short_description = format_markdown(new_short_description) end |
#short_title(new_short_title = nil) ⇒ String
Set/Get a runnable’s short title
228 229 230 231 232 |
# File 'lib/inferno/dsl/runnable.rb', line 228 def short_title(new_short_title = nil) return @short_title if new_short_title.nil? @short_title = new_short_title end |
#suite ⇒ Object
340 341 342 343 344 |
# File 'lib/inferno/dsl/runnable.rb', line 340 def suite return self if ancestors.include? Inferno::Entities::TestSuite parent.suite end |
#suite_endpoint(method, path, endpoint_class) ⇒ void
This method returns an undefined value.
Create an endpoint to receive incoming requests during a Test Run.
406 407 408 |
# File 'lib/inferno/dsl/runnable.rb', line 406 def suite_endpoint(method, path, endpoint_class) route(method, path, endpoint_class) end |
#test_count(selected_suite_options = []) ⇒ Object
429 430 431 432 433 434 435 436 437 438 439 |
# File 'lib/inferno/dsl/runnable.rb', line 429 def test_count( = []) @test_counts ||= {} = .to_json return @test_counts[] if @test_counts[] @test_counts[] = children() &.reduce(0) { |sum, child| sum + child.test_count() } || 0 end |
#title(new_title = nil) ⇒ String
Set/Get a runnable’s title
218 219 220 221 222 |
# File 'lib/inferno/dsl/runnable.rb', line 218 def title(new_title = nil) return @title if new_title.nil? @title = new_title end |
#user_runnable? ⇒ Boolean
442 443 444 445 446 |
# File 'lib/inferno/dsl/runnable.rb', line 442 def user_runnable? @user_runnable ||= parent.nil? || !parent.respond_to?(:run_as_group?) || (parent.user_runnable? && !parent.run_as_group?) end |
#verifies_requirements(*requirement_ids) ⇒ Array<String>
Set/Get the IDs of requirements verified by this runnable Set with [] to clear the list
269 270 271 272 273 274 275 276 277 |
# File 'lib/inferno/dsl/runnable.rb', line 269 def verifies_requirements(*requirement_ids) if requirement_ids.empty? @requirement_ids || [] elsif requirement_ids == [[]] @requirement_ids = [] else @requirement_ids = requirement_ids end end |