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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/bin/qat +5 -0
- data/lib/qat/cli/generator/project.rb +32 -0
- data/lib/qat/cli/generator.rb +48 -0
- data/lib/qat/cli/main.rb +102 -0
- data/lib/qat/cli/plugins/core.rb +19 -0
- data/lib/qat/cli.rb +52 -0
- data/lib/qat/cucumber/core_ext/formatter/html.rb +48 -0
- data/lib/qat/cucumber/core_ext/formatter/junit.rb +57 -0
- data/lib/qat/cucumber/core_ext/result.rb +16 -0
- data/lib/qat/cucumber/core_ext.rb +3 -0
- data/lib/qat/cucumber/hooks/scenario.rb +76 -0
- data/lib/qat/cucumber/hooks.rb +72 -0
- data/lib/qat/cucumber/logger.rb +49 -0
- data/lib/qat/cucumber/time.rb +55 -0
- data/lib/qat/cucumber/version.rb +15 -0
- data/lib/qat/cucumber/world.rb +40 -0
- data/lib/qat/cucumber.rb +76 -0
- data/lib/qat/formatter/console.rb +101 -0
- data/lib/qat/formatter/dashboard.rb +84 -0
- data/lib/qat/formatter/loggable/mdc.rb +74 -0
- data/lib/qat/formatter/loggable/scenario_info.rb +40 -0
- data/lib/qat/formatter/loggable.rb +92 -0
- data/lib/qat/formatter/scenario/name.rb +47 -0
- data/lib/qat/formatter/tags.rb +81 -0
- data/lib/qat/formatter/test_ids.rb +93 -0
- data/lib/qat/jenkins.rb +43 -0
- data/lib/qat/project/Gemfile +13 -0
- data/lib/qat/project/Rakefile +3 -0
- data/lib/qat/project/config/cucumber.yml +13 -0
- data/lib/qat/project/config/default.yml +1 -0
- data/lib/qat/project/config/env-dummy/hosts.yml +9 -0
- data/lib/qat/project/config/env-dummy/jenkins.yml +7 -0
- data/lib/qat/project/config/env-dummy/logger.yml +23 -0
- data/lib/qat/project/config/env-dummy/time.yml +11 -0
- data/lib/qat/project/features/feature.feature +45 -0
- data/lib/qat/project/features/step_definitions/steps.rb +4 -0
- data/lib/qat/project/features/support/env.rb +6 -0
- data/lib/qat/project/features/support/hooks.rb +32 -0
- data/lib/qat/tasks/list.rb +50 -0
- data/lib/qat/tasks/steps.rb +20 -0
- data/lib/qat/tasks/tags/test_ids/helpers.rb +105 -0
- data/lib/qat/tasks/tags/test_ids/report.rb +41 -0
- data/lib/qat/tasks/tags/test_ids.rb +60 -0
- data/lib/qat/tasks/tags.rb +2 -0
- data/lib/qat/tasks/test.rb +35 -0
- data/lib/qat/tasks.rb +8 -0
- metadata +193 -0
data/bin/qat
ADDED
@@ -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'
|
data/lib/qat/cli/main.rb
ADDED
@@ -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>
|
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,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
|