qat-cucumber 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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