qat-cucumber 6.0.0

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 (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/bin/qat +5 -0
  4. data/lib/qat/cli/generator/project.rb +32 -0
  5. data/lib/qat/cli/generator.rb +48 -0
  6. data/lib/qat/cli/main.rb +102 -0
  7. data/lib/qat/cli/plugins/core.rb +19 -0
  8. data/lib/qat/cli.rb +52 -0
  9. data/lib/qat/cucumber/core_ext/formatter/html.rb +48 -0
  10. data/lib/qat/cucumber/core_ext/formatter/junit.rb +57 -0
  11. data/lib/qat/cucumber/core_ext/result.rb +16 -0
  12. data/lib/qat/cucumber/core_ext.rb +3 -0
  13. data/lib/qat/cucumber/hooks/scenario.rb +76 -0
  14. data/lib/qat/cucumber/hooks.rb +72 -0
  15. data/lib/qat/cucumber/logger.rb +49 -0
  16. data/lib/qat/cucumber/time.rb +55 -0
  17. data/lib/qat/cucumber/version.rb +15 -0
  18. data/lib/qat/cucumber/world.rb +40 -0
  19. data/lib/qat/cucumber.rb +76 -0
  20. data/lib/qat/formatter/console.rb +101 -0
  21. data/lib/qat/formatter/dashboard.rb +84 -0
  22. data/lib/qat/formatter/loggable/mdc.rb +74 -0
  23. data/lib/qat/formatter/loggable/scenario_info.rb +40 -0
  24. data/lib/qat/formatter/loggable.rb +92 -0
  25. data/lib/qat/formatter/scenario/name.rb +47 -0
  26. data/lib/qat/formatter/tags.rb +81 -0
  27. data/lib/qat/formatter/test_ids.rb +93 -0
  28. data/lib/qat/jenkins.rb +43 -0
  29. data/lib/qat/project/Gemfile +13 -0
  30. data/lib/qat/project/Rakefile +3 -0
  31. data/lib/qat/project/config/cucumber.yml +13 -0
  32. data/lib/qat/project/config/default.yml +1 -0
  33. data/lib/qat/project/config/env-dummy/hosts.yml +9 -0
  34. data/lib/qat/project/config/env-dummy/jenkins.yml +7 -0
  35. data/lib/qat/project/config/env-dummy/logger.yml +23 -0
  36. data/lib/qat/project/config/env-dummy/time.yml +11 -0
  37. data/lib/qat/project/features/feature.feature +45 -0
  38. data/lib/qat/project/features/step_definitions/steps.rb +4 -0
  39. data/lib/qat/project/features/support/env.rb +6 -0
  40. data/lib/qat/project/features/support/hooks.rb +32 -0
  41. data/lib/qat/tasks/list.rb +50 -0
  42. data/lib/qat/tasks/steps.rb +20 -0
  43. data/lib/qat/tasks/tags/test_ids/helpers.rb +105 -0
  44. data/lib/qat/tasks/tags/test_ids/report.rb +41 -0
  45. data/lib/qat/tasks/tags/test_ids.rb +60 -0
  46. data/lib/qat/tasks/tags.rb +2 -0
  47. data/lib/qat/tasks/test.rb +35 -0
  48. data/lib/qat/tasks.rb +8 -0
  49. metadata +193 -0
data/bin/qat ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: utf-8
3
+
4
+ require 'qat/cli/main'
5
+ QAT::CLI::Main.new(ARGV.dup).execute!
@@ -0,0 +1,32 @@
1
+ require_relative '../../cucumber/version'
2
+ require 'fileutils'
3
+
4
+ module QAT::CLI::Generator
5
+
6
+ #New project generator
7
+ # @since 0.1.0
8
+ class Project
9
+ include FileUtils
10
+
11
+ def initialize stdin=STDIN, stdout=STDOUT, stderr=STDERR, kernel=Kernel
12
+ @fileutils_output = stdout
13
+ end
14
+
15
+ #Create a new project. Will create a new folder with the project's name.
16
+ #@param name [String] The new project's name
17
+ def run! name, opts={}
18
+
19
+ raise ArgumentError.new 'No project name given' unless name
20
+ raise ArgumentError.new "The project '#{name}' already exists" if ::File.directory? name
21
+
22
+ mkdir name, opts
23
+ cp_r ::File.join(::File.dirname(__FILE__), '..', '..', 'project', '.'), name, opts
24
+ cd name, opts do
25
+ mkdir_p ::File.join('config', 'common'), opts
26
+ mkdir_p 'lib', opts
27
+ mkdir_p 'public', opts
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ require_relative '../cucumber/version'
2
+
3
+ module QAT::CLI
4
+ #Module for the various generators used in the CLI utility
5
+ # @since 0.1.0
6
+ module Generator
7
+ # Creates a new QAT project with a given name
8
+ # @param name [String] project name
9
+ def create_project(name)
10
+ QAT::CLI::Generator::Project.new(@stdin, @stdout, @stderr, @kernel).run! name, @sub_options
11
+
12
+ if @options.has_key? :modules
13
+ FileUtils.cd name, @sub_options do
14
+ add_modules(@options[:modules])
15
+ end
16
+ end
17
+ end
18
+
19
+ # Adds QAT modules to the current project
20
+ # @param modules [Array] list of modules' names to add
21
+ def add_modules(modules)
22
+ missing_modules = modules.reject { |mod| QAT::CLI.has_module? mod }
23
+
24
+ if missing_modules.any?
25
+ raise ArgumentError.new "Module#{missing_modules.size > 1 ? 's' : ''} #{missing_modules.join ','} missing!"
26
+ end
27
+
28
+ modules.each do |module_name|
29
+ add_module(module_name)
30
+ end
31
+ end
32
+
33
+ # Adds a QAT module to the current project
34
+ # @param name [String] name of module to add
35
+ def add_module(name)
36
+ @stdout.puts "Adding module #{name}" if @sub_options[:verbose]
37
+ begin
38
+ QAT::CLI.add_module name, @stdout, @sub_options
39
+ @stdout.puts "Module #{name} added to #{Dir.getwd.split(::File::SEPARATOR).last}"
40
+ rescue => exception
41
+ @stderr.puts "Error adding module #{name}: #{exception.message}"
42
+ @exit_code = 1
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ require_relative 'generator/project'
@@ -0,0 +1,102 @@
1
+ require_relative '../cli'
2
+ require_relative '../cucumber/version'
3
+ require_relative 'generator'
4
+ require 'optparse'
5
+ require 'fileutils'
6
+ require 'time'
7
+
8
+ #Main class for the CLI.
9
+ #@since 0.1.0
10
+ class QAT::CLI::Main
11
+ include QAT::CLI::Generator
12
+
13
+ #Initialization from command line
14
+ def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
15
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
16
+ @options = {}
17
+ @sub_options = {}
18
+ @exit_code = 0
19
+ end
20
+
21
+ #Main entry point for execution
22
+ def execute!
23
+ parse_argv!
24
+
25
+ handle_options if @options.any?
26
+
27
+ rescue ArgumentError, OptionParser::MissingArgument => exception
28
+ @stderr.puts "Error: #{exception.message}"
29
+ @exit_code = 1
30
+ ensure
31
+ @kernel.exit(exit_code)
32
+ end
33
+
34
+ private
35
+
36
+ attr_accessor :exit_code
37
+
38
+ def parse_argv!
39
+ @argv = ['-h'] if @argv.empty?
40
+
41
+ opts = OptionParser.new do |parser|
42
+ parser.banner = 'Usage: qat [OPTIONS]'
43
+ # parser.separator ''
44
+ parser.separator 'Options'
45
+
46
+ project_options(parser)
47
+ end
48
+
49
+ opts.parse!(@argv)
50
+ end
51
+
52
+ def handle_options
53
+ if @options.has_key? :project
54
+ create_project(@options[:project])
55
+ elsif @options.has_key? :modules
56
+ add_modules(@options[:modules])
57
+ end
58
+ end
59
+
60
+ def project_options(parser)
61
+ parser.on('-n', '--new [NAME]', String, 'Create new project') do |project|
62
+ @options[:project] = project
63
+ end
64
+
65
+ parser.on('-a', '--add [MODULES]', Array, 'Integrate modules in project') do |modules|
66
+ @options[:modules] = parse_modules(modules)
67
+ end
68
+
69
+ parser.on('-l', '--list', 'Show available modules') do
70
+ list_available_modules
71
+ @exit_code = 0
72
+ end
73
+
74
+ parser.on('-r', '--verbose', 'Show detailed information') do
75
+ @sub_options[:verbose] = true
76
+ end
77
+
78
+ parser.on('-v', '--version', 'Show QAT-Cucumber version') do
79
+ @stdout.puts QAT::Cucumber::VERSION
80
+ @exit_code = 0
81
+ end
82
+
83
+ parser.on('-h', '--help', 'Show this helper') do
84
+ @stdout.puts parser.help
85
+ @exit_code = 0
86
+ end
87
+ end
88
+
89
+ def parse_modules(modules)
90
+ modules = modules.to_a
91
+ existing_modules = @options[:modules]
92
+ existing_modules ? existing_modules + modules : modules
93
+ end
94
+
95
+ def list_available_modules
96
+ modules = QAT::CLI.list_extentions
97
+
98
+ @stdout.puts 'List of available modules:'
99
+ names = modules.map { |module_name| "\t#{module_name}" }
100
+ @stdout.puts names.join("\n")
101
+ end
102
+ end
@@ -0,0 +1,19 @@
1
+ module QAT
2
+ module CLI
3
+ module Plugins
4
+ #Plugin for CLI functions
5
+ #@since 0.1.0
6
+ module Core
7
+
8
+ #Function for adding the Core module to a project. Just used for testing, does nothing.
9
+ #@param stdout [IO] Stdout stream
10
+ #@param opts [Hash] Options hash
11
+ #@since 0.1.0
12
+ def self.add_module stdout, opts
13
+ stdout.puts 'Nothing to add in Core module' if opts[:verbose]
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
data/lib/qat/cli.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'little-plugger'
2
+
3
+ module QAT
4
+ #Module for CLI functions
5
+ #@since 0.1.0
6
+ module CLI
7
+ #Module as namespace for plugin definition
8
+ #@since 0.1.0
9
+ module Plugins
10
+ #Placeholder
11
+ end
12
+ # @!parse extend LittlePlugger
13
+ send :extend, LittlePlugger( :path => 'qat/cli/plugins', :module => ::QAT::CLI::Plugins )
14
+
15
+ #Lists all registered extentions/plugins
16
+ #@since 0.1.0
17
+ def self.list_extentions
18
+ plugins.keys.map(&:to_s).sort
19
+ end
20
+
21
+ #Call add_module in a given plugin.
22
+ #@param mod [String,Symbol] name of the plugin to call
23
+ #@param stdout [IO] stdout stream
24
+ #@param opts [Hash] options hash
25
+ #@raise ArgumentError When module does not exist
26
+ #@since 0.1.0
27
+ def self.add_module mod, stdout, opts
28
+ raise ArgumentError.new "Module #{mod} is not a plugin!" unless has_module? mod
29
+
30
+ loaded_mod = plugins[mod.to_sym]
31
+
32
+ if loaded_mod.respond_to? :add_module
33
+ meth = loaded_mod.method :add_module
34
+ unless meth.arity == 2 || meth.arity < 0
35
+ raise ArgumentError.new "Invalid implementation of add_module in #{mod}: should have 2 parameters: stdout, opts"
36
+ end
37
+ meth.call stdout, opts
38
+ else
39
+ stdout.puts "Nothing to add in #{mod}"
40
+ end
41
+ end
42
+
43
+
44
+ #Check if a plugin exists
45
+ #@param mod [String,Symbol] name of the plugin to call
46
+ #@return [true,false] true if the plugin exists
47
+ #@since 0.1.0
48
+ def self.has_module? mod
49
+ return plugins.has_key? mod.to_sym
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,48 @@
1
+ require 'cucumber/formatter/html'
2
+
3
+ #Extension to the cucumber module adding the embed video options
4
+ module Cucumber
5
+ #Extension to the formatter module adding the embed video options
6
+ module Formatter
7
+ #Extension to the html class adding the embed video options
8
+ class Html
9
+ #Method embed that also contains options to embed video case the extension is met
10
+ def embed(src, mime_type, label)
11
+ case (mime_type)
12
+ when /^image\/(png|gif|jpg|jpeg)/
13
+ unless File.file?(src) or src =~ /^data:image\/(png|gif|jpg|jpeg);base64,/
14
+ type = mime_type =~ /;base[0-9]+$/ ? mime_type : mime_type + ";base64"
15
+ src = "data:" + type + "," + src
16
+ end
17
+ embed_image(src, label)
18
+ when /^text\/plain/
19
+ embed_text(src, label)
20
+ when /^video\/\w+/
21
+ embed_video(src,mime_type, label)
22
+ end
23
+ end
24
+
25
+ #Method to embed the video in the HTML Report
26
+ def embed_video(src,mime_type, label)
27
+ @video_id ||= 0
28
+
29
+ if @io.respond_to?(:path) and File.file?(src)
30
+ out_dir = Pathname.new(File.dirname(File.absolute_path(@io.path)))
31
+ src = Pathname.new(File.absolute_path(src)).relative_path_from(out_dir)
32
+ end
33
+
34
+ @builder.span(:class => 'embed') do |pre|
35
+ pre << %{
36
+ <a href="" onclick="video=document.getElementById('video_div_#{@video_id}'); video.style.display = (video.style.display == 'none' ? 'block' : 'none');return false"><br>#{label}</a><br>&nbsp;
37
+ <div id="video_div_#{@video_id}" style="display: none">
38
+ <video id="video_#{@video_id}" autostart="0" width="800" height="600" controls> <source src="#{src}" type="#{mime_type}" ></video><br>
39
+ <a href="#{src}" download="#{src}">Download Video</a>
40
+ </div>}
41
+ end
42
+
43
+ @video_id += 1
44
+ end
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,57 @@
1
+ require 'cucumber/formatter/junit'
2
+
3
+ module Cucumber
4
+ module Formatter
5
+ # The formatter used for <tt>--format junit</tt>
6
+ class Junit
7
+
8
+ #Method to parse time in testsuite elements
9
+ def end_feature(feature_data)
10
+ @testsuite = Builder::XmlMarkup.new(:indent => 2)
11
+ @testsuite.instruct!
12
+ @testsuite.testsuite(
13
+ :failures => feature_data[:failures],
14
+ :errors => feature_data[:errors],
15
+ :skipped => feature_data[:skipped],
16
+ :tests => feature_data[:tests],
17
+ :time => "%.3f" % feature_data[:time],
18
+ :name => feature_data[:feature].name) do
19
+ @testsuite << feature_data[:builder].target!
20
+ end
21
+
22
+ write_file(feature_result_filename(feature_data[:feature].file), @testsuite.target!)
23
+ end
24
+
25
+ #Method to parse time in testcase elements
26
+ def build_testcase(result, scenario_designation, output)
27
+ duration = ResultBuilder.new(result).test_case_duration
28
+ @current_feature_data[:time] += duration
29
+ classname = @current_feature_data[:feature].name
30
+ name = scenario_designation
31
+
32
+ @current_feature_data[:builder].testcase(:classname => classname, :name => name, :time => "%.3f" % duration) do
33
+ if !result.passed? && result.ok?(@config.strict?)
34
+ @current_feature_data[:builder].skipped
35
+ @current_feature_data[:skipped] += 1
36
+ elsif !result.passed?
37
+ status = result.to_sym
38
+ exception = get_backtrace_object(result)
39
+ @current_feature_data[:builder].failure(:message => "#{status} #{name}", :type => status) do
40
+ @current_feature_data[:builder].cdata! output
41
+ @current_feature_data[:builder].cdata!(format_exception(exception)) if exception
42
+ end
43
+ @current_feature_data[:failures] += 1
44
+ end
45
+ @current_feature_data[:builder].tag!('system-out') do
46
+ @current_feature_data[:builder].cdata! strip_control_chars(@interceptedout.buffer.join)
47
+ end
48
+ @current_feature_data[:builder].tag!('system-err') do
49
+ @current_feature_data[:builder].cdata! strip_control_chars(@interceptederr.buffer.join)
50
+ end
51
+ end
52
+ @current_feature_data[:tests] += 1
53
+ end
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,16 @@
1
+ require 'cucumber/core/test/result'
2
+
3
+ #Patch for Cucumber::Core::Test::Result::Unknown to implement methods used by the formatters
4
+ #@since 1.1.0
5
+ class Cucumber::Core::Test::Result::Unknown
6
+
7
+ #Dummy function
8
+ def with_appended_backtrace(_)
9
+ ''
10
+ end
11
+
12
+ #Dummy function
13
+ def with_filtered_backtrace(_)
14
+ ''
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'core_ext/result'
2
+ require_relative 'core_ext/formatter/html'
3
+ require_relative 'core_ext/formatter/junit'
@@ -0,0 +1,76 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'cucumber'
3
+ require 'qat/logger'
4
+
5
+ module QAT
6
+ module Cucumber
7
+ #Methods to execute with Cucumber Hooks and at_exit.
8
+ #@since 0.1.0
9
+ module Hooks
10
+ module Scenario
11
+ include QAT::Logger
12
+
13
+ def scenario_tags(scenario)
14
+ scenario.tags.map { |tag| tag.name }.compact
15
+ end
16
+
17
+ def define_test_id(scenario)
18
+ test_id = "#{test_id(scenario)}"
19
+
20
+ QAT[:current_test_id] = test_id
21
+ QAT[:current_test_run_id] = "#{test_id}_#{QAT[:test_start_timestamp].to_i}"
22
+ log.info "Scenario has test id: #{QAT[:current_test_id]} and test run id: #{QAT[:current_test_run_id]}"
23
+ end
24
+
25
+ private
26
+ def test_id(scenario)
27
+ outline_id = get_outline_id(scenario)
28
+
29
+ tags = scenario_tags(scenario)
30
+ tag = tags.select { |tag| tag.match /^\@test\#/ }.first
31
+ test_id = if tag
32
+ tag.gsub '@test#', 'test_'
33
+ else
34
+ log.warn "Scenario does not have a test id! Using a dummy one..."
35
+ 'test_0'
36
+ end
37
+
38
+ "#{test_id}#{outline_id}"
39
+ end
40
+
41
+ def get_outline_id(scenario)
42
+ if scenario.is_a? ::Cucumber::RunningTestCase::ScenarioOutlineExample
43
+ test_case = scenario.instance_exec { @test_case }
44
+ test_case_source = test_case.source
45
+
46
+ tables = get_example_tables(test_case_source)
47
+ table_lines = get_examples_size(tables)
48
+ table_num = current_outline_index(tables, test_case_source)
49
+ previous_outlines = count_previous_outlines(table_lines, table_num)
50
+ "_#{previous_outlines + test_case_source[3].number}"
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ def get_example_tables(test_case_source)
57
+ test_case_source[1].instance_exec { @examples_tables }
58
+ end
59
+
60
+ def get_examples_size(tables)
61
+ tables.each.map { |table| table.example_rows.size }
62
+ end
63
+
64
+ def current_outline_index(tables, test_case_source)
65
+ tables.index test_case_source[2]
66
+ end
67
+
68
+ def count_previous_outlines(table_lines, table_num)
69
+ table_lines[0...table_num].inject(0) { |sum, lines| sum += lines; sum }
70
+ end
71
+
72
+ extend self
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,72 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'cucumber'
3
+ require 'fileutils'
4
+ require 'tmpdir'
5
+ require 'qat/time'
6
+ require_relative 'version'
7
+ require_relative 'hooks/scenario'
8
+
9
+ module QAT
10
+ module Cucumber
11
+ #Methods to execute with Cucumber Hooks and at_exit.
12
+ #@since 0.1.0
13
+ module Hooks
14
+ include QAT::Logger
15
+
16
+ class << self
17
+ #Hook to be executed before a scenario. It executes the following actions:
18
+ # * save scenario tags (Saved in {QAT::Core} with the :scenario_tags key)
19
+ # * save current test start timestamp (Saved in {QAT::Core} with the :test_start_timestamp key)
20
+ # * create a temporary folder (Saved in {QAT::Core} with the :tmp_folder key)
21
+ def before(scenario)
22
+ QAT.reset!
23
+
24
+ QAT.store :scenario_tags, Scenario.scenario_tags(scenario)
25
+ QAT.store :test_start_timestamp, QAT::Time.now
26
+ QAT.store :tmp_folder, Dir.mktmpdir
27
+
28
+ Scenario.define_test_id(scenario)
29
+ rescue => error
30
+ log.warn { error }
31
+ end
32
+
33
+ def after_step
34
+ #TODO
35
+ rescue => error
36
+ log.warn { error }
37
+ end
38
+
39
+ #Hook to be executed after a scenario. It executes the following actions:
40
+ # * delete the temporary folder
41
+ # * reset the cache
42
+ def after(_)
43
+ FileUtils.rm_r QAT[:tmp_folder]
44
+ rescue => error
45
+ log.warn { error }
46
+ end
47
+
48
+ def at_exit
49
+ #TODO
50
+ rescue => error
51
+ log.warn { error }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ Before do |scenario|
59
+ QAT::Cucumber::Hooks.before(scenario)
60
+ end
61
+
62
+ AfterStep do
63
+ QAT::Cucumber::Hooks.after_step
64
+ end
65
+
66
+ After do |scenario|
67
+ QAT::Cucumber::Hooks.after(scenario)
68
+ end
69
+
70
+ at_exit do
71
+ QAT::Cucumber::Hooks.at_exit
72
+ end
@@ -0,0 +1,49 @@
1
+ module QAT
2
+ module Cucumber
3
+ # Helper methods for logger configuration
4
+ # @since 2.0.2
5
+ module Logger
6
+ # Configures Logger with a given configuration
7
+ # @param configuration [Hash] logger configuration
8
+ def config_logger(configuration)
9
+ config = validate_logger_config(configuration)
10
+
11
+ load_logger_config(config) if config
12
+ end
13
+
14
+ # Validates that a valid logger configuration exists in the QAT environment variable
15
+ # @param configuration [Hash] logger configuration
16
+ def validate_logger_config(configuration)
17
+ logger_env_config = ENV['QAT_LOGGER_CONFIG']
18
+
19
+ if logger_env_config
20
+ raise InvalidConfiguration.new "Configuration file for logger does not exist: '#{logger_env_config}'" unless File.exists?(logger_env_config.to_s)
21
+ logger_env_config
22
+ else
23
+ validate_logger_yaml_config(configuration)
24
+ end
25
+ end
26
+
27
+ # Validates that a valid logger configuration exists in a YAML file
28
+ # @param configuration [Hash] logger configuration
29
+ def validate_logger_yaml_config(configuration)
30
+ configuration_directory = configuration.directory
31
+
32
+ files = [File.join(configuration_directory, configuration.environment, 'logger.yml'),
33
+ File.join(configuration_directory, 'common', 'logger.yml')]
34
+
35
+ config = files.select { |file| File.exists?(file) }
36
+
37
+ config.first
38
+ end
39
+
40
+ # Loads the logger configuration
41
+ # @param to_load [Hash] logger configuration to load
42
+ def load_logger_config(to_load)
43
+ Log4r::YamlConfigurator.load_yaml_file(to_load)
44
+
45
+ log.info { "Loaded logger configuration from file '#{to_load}'" }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,55 @@
1
+ module QAT
2
+ module Cucumber
3
+ # Helper methods for time sync
4
+ # @since 2.0.2
5
+ module Time
6
+ include QAT::Logger
7
+
8
+ # Mandatory keys for time sync
9
+ MANDATORY_KEYS = [:sync]
10
+
11
+ # Does the time synchronization between the host running tests and a target host
12
+ def time_sync
13
+ time = validate_time_options
14
+
15
+ sync_options = time[:sync]
16
+ log.info { "Syncing with host #{sync_options[:host]}." }
17
+ target = sync_options.values_at(:host, :method, :opts)
18
+
19
+ start_time_sync(target, sync_options)
20
+
21
+ set_time_zone(time[:zone])
22
+ end
23
+
24
+ # validates that the necessary options are present
25
+ def validate_time_options
26
+ time = QAT.configuration[:time].deep_symbolize_keys
27
+ missing = MANDATORY_KEYS - time.keys
28
+
29
+ raise InvalidConfiguration.new "Time configuration is not valid! Missing: #{missing.join(', ')}" if missing.any?
30
+
31
+ time
32
+ end
33
+
34
+ # Does the time sync with the target host
35
+ # @param target [Array] host, method of sync, options
36
+ # @param sync_options [Hash] sync options
37
+ def start_time_sync(target, sync_options)
38
+ QAT::Time.synchronize(*target)
39
+ rescue => exception
40
+ if sync_options[:kill_if_failed]
41
+ raise
42
+ else
43
+ log.warn { "Synchronization failed but proceeding anyway! [(#{exception.class}) #{exception.message}]" }
44
+ log.debug exception
45
+ end
46
+ end
47
+
48
+ # Sets the time zone
49
+ # @param time_zone [String] time zone
50
+ def set_time_zone(time_zone)
51
+ QAT::Time.zone = time_zone if time_zone
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,15 @@
1
+ #encoding: utf-8
2
+
3
+ #QAT Module works as a namespace for all sub modules.
4
+ #Some singleton methods are also available, as defined by various sub classes.
5
+ #@since 0.1.0
6
+ module QAT
7
+ # Namespace for various helpers when running with cucumber.
8
+ #Just require 'qat/cucumber' to automatically integrate all the available helpers.
9
+ #
10
+ #@since 0.1.0
11
+ module Cucumber
12
+ # Represents QAT's version
13
+ VERSION = '6.0.0'
14
+ end
15
+ end