require_relative 'container/version' require 'yaml' require 'ostruct' require 'json' require 'rake' require 'colorize' module Henry # Henry Container class Container # Initialize the Container with the given options # # @param [Hash] the execution given options. def initialize(opts) @opts = opts end # Executes the loaded tasks and stores their results. def execute self.before_execution self.tasks.select {|task| task.enabled?}.each do |task| self.task_params(task.name).each do |task_params| task.configure(task_params, self.task_extended_context(task.name)) task.before_execute task.execute task.after_execute self.tasks_results << task.report end end self.update_results self.dump_results end protected # Initial state the conteiner execution results. # # @return [Hash] the results template. RESULTS_TEMPLATE = { summary: { total: 0, breakdownByStatusCode: { 'OK' => 0, 'ERROR' => 0, 'WARNING' => 0 }, tasks: [] } } # Returns the input file path based on the given options. # # @return [String] the input file path. def input_file_path "#{@opts[:"in-dir"]}/#{@opts[:in]}" end # Returns the output file path based on the given options. # # @return [String] the output file path. def output_file_path "#{@opts[:"out-dir"]}/#{@opts[:out]}" end # Returns the task hints file path based on the given options. # # @return [String] the task hints file path. def hints_file_path "#{@opts[:"hints-dir"]}/#{@opts[:hints]}" end # Returns the task hints patched file path based on the given options. # # @return [String] the task hints file path. def hints_file_patched_path "#{@opts[:"in-dir"]}/#{@opts[:hints]}" end # Executes required validations before execution. def before_execution unless File.exists?('henry-context.yml') abort "'henry-context.yml' file does not exist. You need it in order to execute a Henry compatible test.".red end end # Returns the execution params. # # @return [{String => String}] the execution params. def params @params ||= self.load_params end # Loads and parses the @opts[:in] params, if they exists. # # @return [{String => String}] the execution params. def load_params return [{}] unless File.exists?(self.input_file_path) JSON.parse(File.read(self.input_file_path)) end # Returns the default params. # @note Custom task_params will overwrite the defaults. # # @return [Hash] the default params. def default_params @default_params ||= (self.params['all'] || {}) end # Returns the custom params for the given task. # @note default_params will be used for undefined keys. # # @param [String] task_name the target Task name. # @return [Array] the Task custom params. def task_params(task_name) self.params.collect do |params| (params['all'] || {}).merge(params[task_name] || {}) end end # Return the default extended execution. # @note Custom extended_executions will overwrite the defaults. # # @return [Hash] the Task default extended context def default_extended_context {} end # Retrun the custom extended_context fo the given task. # @note default_extended_context will be used for undefined keys. # # @param [String] task_name the target Task name. # @return [Hash] the Task custom extended context. def extended_context(task_name) (self.params[task_name] || {})['extended_context'] end # Returns the custom execution_context for the given task. # @note default_execution_context will be used for undefined keys. # # @param [String] task_name the target Task name. # @return [Hash] the Task custom execution_context. def task_extended_context(task_name) self.default_extended_context.merge(self.extended_context(task_name) || {}) end # Returns de task hints (tasks to be executed) or an empty array if they are not defined. # # @return [] the task hints. def task_hints self.hints["tasks"] || [] end # Returns de hints or an empty Hash if they are not defined. # # @return [Hash] the hints. def hints @hints ||= self.load_hints end # Loads and parses the @opts[:hints] params, if they exists. # # @return [Hash] the hints:w def load_hints # To be removed once that the Worker starts using the --hints-path if File.exists?(self.hints_file_patched_path) return JSON.parse(File.read(self.hints_file_patched_path)) end return {} unless File.exists?(self.hints_file_path) JSON.parse(File.read(self.hints_file_path)) end # Load and parses the henry-context.yml params. # # @return [{String => String}] the execution context. def context @context ||= OpenStruct.new(YAML.load_file('henry-context.yml')) end # Returns the tasks to be executed based on the context. # # @return [] tasks to be executed. def tasks @tasks ||= self.build_tasks end # Builds and disables the Tasks to be executed based on the context and hints. # # @return [] tasks to be executed. def build_tasks tasks = self.context.tasks.collect do |task_data| Task.create(task_data["name"], task_data) end return tasks if self.task_hints.empty? tasks.each do |task| task.disable! unless self.task_hints.include? task.name end end # Returns the execution's current results. # # @return [Hash] the execution's current resutls. def results @results ||= RESULTS_TEMPLATE end # Returns the tasks_results node from the results hash. # # @return [Array] def tasks_results self.results[:summary][:tasks] end # Serts the tasks_results node of the results hash. # # @param [Array] results the tasks_results collection. def tasks_results=(results) self.results[:summary][:tasks] = results end # Updates the results attributes based on the task_results. def update_results self.tasks_results.each do |task_results| self.results[:summary][:total] += 1 self.results[:summary][:breakdownByStatusCode][task_results[:code]] += 1 end end # Writes into @opts[:out] the execution results. def dump_results File.open(self.output_file_path, 'w') { |f| f.write(results.to_json) } end end end