moto 0.9.11 → 0.9.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/moto +10 -2
- data/lib/empty_listener.rb +16 -16
- data/lib/exceptions/{moto.rb → base.rb} +1 -1
- data/lib/exceptions/test_forced_failure.rb +3 -1
- data/lib/exceptions/test_forced_passed.rb +3 -1
- data/lib/exceptions/test_skipped.rb +3 -1
- data/lib/modes/generate/test_template_generator.rb +82 -0
- data/lib/modes/mode_selector.rb +78 -0
- data/lib/modes/run/dry_runner.rb +40 -0
- data/lib/modes/run/test_provider.rb +71 -0
- data/lib/modes/run/test_runner.rb +74 -0
- data/lib/modes/run/thread_context.rb +81 -0
- data/lib/modes/validate/test_validator.rb +87 -0
- data/lib/parameter_parser.rb +282 -0
- data/lib/reporting/test_reporter.rb +0 -1
- data/lib/test/base.rb +0 -2
- data/lib/{runner/test_generator.rb → test/generator.rb} +26 -23
- data/lib/test/metadata.rb +1 -1
- data/lib/test/metadata_generator.rb +78 -0
- data/lib/test/status.rb +0 -3
- data/lib/version.rb +1 -1
- metadata +14 -14
- data/lib/app_generator.rb +0 -80
- data/lib/cli.rb +0 -120
- data/lib/initializer.rb +0 -7
- data/lib/parser.rb +0 -182
- data/lib/reporting/listeners/webui_deprecated.rb +0 -127
- data/lib/runner/dry_runner.rb +0 -37
- data/lib/runner/test_provider.rb +0 -68
- data/lib/runner/test_runner.rb +0 -71
- data/lib/runner/thread_context.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fd7651cf81d31a19644da80e0837649daa58e57
|
4
|
+
data.tar.gz: a3ab1acad8e60e01cfb3ea2a40e2738226addb8a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8eca0bcbda114f618032f367494e1c53fa7d7fb9bfd5153baf40de7d8e487ec5889cb4a5c07f2f1e110711a122dd162c4c7294ffe3bdadd890c46befc5a7e281
|
7
|
+
data.tar.gz: 0e33fcc4ebbe3efcc9ca3142e00f70732edddf4c0f04d0516c4454b53dfbcc4ee366668462bcac0a2573c4d54478952f69ef7f3fd58dfc9b81e2aa2bb0847995
|
data/bin/moto
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require_relative '../lib/
|
3
|
+
require_relative '../lib/test_logging'
|
4
|
+
require_relative '../lib/test/base'
|
4
5
|
|
5
|
-
|
6
|
+
require_relative '../lib/reporting/listeners/base'
|
7
|
+
require_relative '../lib/reporting/listeners/console'
|
8
|
+
require_relative '../lib/reporting/listeners/console_dots'
|
9
|
+
require_relative '../lib/reporting/listeners/junit_xml'
|
10
|
+
require_relative '../lib/reporting/listeners/webui'
|
11
|
+
|
12
|
+
require_relative '../lib/parameter_parser'
|
13
|
+
Moto::ParameterParser.parse_user_input(ARGV)
|
data/lib/empty_listener.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
module Moto
|
2
|
-
module EmptyListener
|
3
|
-
|
4
|
-
def start_run
|
5
|
-
end
|
6
|
-
|
7
|
-
def end_run
|
8
|
-
end
|
9
|
-
|
10
|
-
def start_test(test)
|
11
|
-
end
|
12
|
-
|
13
|
-
def end_test(test)
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
1
|
+
module Moto
|
2
|
+
module EmptyListener
|
3
|
+
|
4
|
+
def start_run
|
5
|
+
end
|
6
|
+
|
7
|
+
def end_run
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_test(test)
|
11
|
+
end
|
12
|
+
|
13
|
+
def end_test(test)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
17
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Moto
|
4
|
+
module Modes
|
5
|
+
module Generate
|
6
|
+
class TestTemplateGenerator
|
7
|
+
|
8
|
+
# Creates directories and file with class template for a test.
|
9
|
+
# @param options [Hash] Informations required perfrom the task.
|
10
|
+
# options[:app_name] Name of the application that uses Moto Framework.
|
11
|
+
# options[:dir] Subdirectories of MotoApp/tests/ where test should be placed.
|
12
|
+
# options[:base_class] Path and filename of class from which the test will derive.
|
13
|
+
# options[:force] Whether generator should forcibly overwrite previously existing file.
|
14
|
+
def self.run(options)
|
15
|
+
|
16
|
+
# Build list of modules basing on the name of the application and subdirectory provided by the user.
|
17
|
+
# Second module is always 'tests' since it's where they should be kept.
|
18
|
+
modules = [options[:app_name], 'tests'] + options[:dir].split('/')
|
19
|
+
modules.map!(&:camelize)
|
20
|
+
|
21
|
+
# Name of the class in the template
|
22
|
+
class_name = modules.last
|
23
|
+
|
24
|
+
# Evaluate fully qualified name of the class to derive from or, if not specified
|
25
|
+
# use Moto's default one
|
26
|
+
if options[:base_class].nil?
|
27
|
+
base_class_qualified_name = 'Moto::Test::Base'
|
28
|
+
else
|
29
|
+
base_class_qualified_name = "#{options[:app_name]}::Lib::Test::#{options[:base_class].split('/').join('::').camelize}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Where to put finished template
|
33
|
+
test_file = File.basename(options[:dir]) + '.rb'
|
34
|
+
test_dir = MotoApp::DIR + '/tests/' + options[:dir]
|
35
|
+
test_path = "#{test_dir}/#{test_file}"
|
36
|
+
|
37
|
+
# Create directory
|
38
|
+
FileUtils.mkdir_p(test_dir)
|
39
|
+
|
40
|
+
if !File.exist?(test_path) || options[:force]
|
41
|
+
# Create new file in specified location and add class' template to it
|
42
|
+
File.open(test_path, 'w+') do |file|
|
43
|
+
|
44
|
+
indent = 0
|
45
|
+
|
46
|
+
if options[:base_class].nil?
|
47
|
+
file << "\n"
|
48
|
+
else
|
49
|
+
file << "require './lib/test/#{options[:base_class]}.rb'\n\n"
|
50
|
+
end
|
51
|
+
|
52
|
+
modules.each do |m|
|
53
|
+
file << (' ' * indent) + "module #{m}\n"
|
54
|
+
indent += 2
|
55
|
+
end
|
56
|
+
|
57
|
+
file << (' ' * indent) + "# Class template genereated by 'moto generate'\n"
|
58
|
+
file << (' ' * indent) + "class #{class_name} < #{base_class_qualified_name}\n\n"
|
59
|
+
indent += 2
|
60
|
+
file << (' ' * indent) + "def run\n"
|
61
|
+
file << (' ' * indent) + "end\n\n"
|
62
|
+
indent -= 2
|
63
|
+
file << (' ' * indent) + "end\n"
|
64
|
+
|
65
|
+
modules.each do
|
66
|
+
indent -= 2
|
67
|
+
file << (' ' * indent) + "end\n"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
puts 'Result:'
|
73
|
+
puts " File: #{test_path}"
|
74
|
+
puts " Class: #{class_name} < #{base_class_qualified_name}"
|
75
|
+
else
|
76
|
+
raise 'File already exists. Use -f or --force to overwrite existing contents.'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative '../reporting/test_reporter'
|
2
|
+
|
3
|
+
require_relative '../test/metadata_generator'
|
4
|
+
|
5
|
+
require_relative 'generate/test_template_generator'
|
6
|
+
require_relative 'run/dry_runner'
|
7
|
+
require_relative 'run/test_runner'
|
8
|
+
require_relative 'validate/test_validator'
|
9
|
+
|
10
|
+
|
11
|
+
module Moto
|
12
|
+
module Modes
|
13
|
+
class ModeSelector
|
14
|
+
|
15
|
+
def run(parsed_arguments)
|
16
|
+
tests_metadata = prepare_metadata(parsed_arguments)
|
17
|
+
test_reporter = prepare_test_reporter(parsed_arguments)
|
18
|
+
|
19
|
+
if Moto::Lib::Config.moto[:test_runner][:dry_run]
|
20
|
+
runner = Moto::Modes::Run::DryRunner.new(tests_metadata, test_reporter)
|
21
|
+
else
|
22
|
+
runner = Moto::Modes::Run::TestRunner.new(tests_metadata, test_reporter, parsed_arguments[:stop_on])
|
23
|
+
end
|
24
|
+
|
25
|
+
runner.run
|
26
|
+
end
|
27
|
+
|
28
|
+
def generate(parsed_arguments)
|
29
|
+
Moto::Modes::Generate::TestTemplateGenerator.run(parsed_arguments)
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate(parsed_arguments)
|
33
|
+
tests_metadata = prepare_metadata(parsed_arguments)
|
34
|
+
test_reporter = prepare_test_reporter(parsed_arguments)
|
35
|
+
|
36
|
+
validation_options = {}
|
37
|
+
validation_options[:tags_regex_positive] = parsed_arguments[:validator_regex_positive] if parsed_arguments[:validator_regex_positive]
|
38
|
+
validation_options[:tags_regex_negative] = parsed_arguments[:validator_regex_negative] if parsed_arguments[:validator_regex_negative]
|
39
|
+
validation_options[:has_tags] = parsed_arguments.key?(:validate_has_tags)
|
40
|
+
validation_options[:has_description] = parsed_arguments.key?(:validate_has_description)
|
41
|
+
validation_options[:tag_whitelist] = parsed_arguments[:tag_whitelist] if parsed_arguments[:tag_whitelist]
|
42
|
+
|
43
|
+
validator = Moto::Modes::Validate::TestValidator.new(tests_metadata, validation_options, test_reporter)
|
44
|
+
validator.run
|
45
|
+
end
|
46
|
+
|
47
|
+
def version
|
48
|
+
puts Moto::VERSION
|
49
|
+
end
|
50
|
+
|
51
|
+
def prepare_metadata(parsed_arguments)
|
52
|
+
tests_metadata = Moto::Test::MetadataGenerator.generate(parsed_arguments[:tests],
|
53
|
+
parsed_arguments[:tags],
|
54
|
+
parsed_arguments[:filters])
|
55
|
+
|
56
|
+
# TODO Display criteria used
|
57
|
+
if tests_metadata.empty?
|
58
|
+
puts 'No tests found for given arguments.'
|
59
|
+
Kernel.exit(-1)
|
60
|
+
else
|
61
|
+
return tests_metadata
|
62
|
+
end
|
63
|
+
end
|
64
|
+
private :prepare_metadata
|
65
|
+
|
66
|
+
def prepare_test_reporter(parsed_arguments)
|
67
|
+
run_params = {}
|
68
|
+
run_params[:run_name] = parsed_arguments[:run_name]
|
69
|
+
run_params[:suite_name] = parsed_arguments[:suite_name]
|
70
|
+
run_params[:assignee] = parsed_arguments[:assignee]
|
71
|
+
|
72
|
+
Moto::Reporting::TestReporter.new(parsed_arguments[:listeners], run_params)
|
73
|
+
end
|
74
|
+
private :prepare_test_reporter
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require_relative '../../reporting/test_reporter'
|
2
|
+
require_relative '../../test/generator'
|
3
|
+
|
4
|
+
module Moto
|
5
|
+
module Modes
|
6
|
+
module Run
|
7
|
+
class DryRunner
|
8
|
+
|
9
|
+
# @param [Array] tests_metadata Collection of [Moto::Test::Metadata] objects describing Tests
|
10
|
+
# @param [Moto::Reporting::TestReporter] test_reporter Reporter of test/run statuses that communicates with external status listeners
|
11
|
+
def initialize(tests_metadata, test_reporter)
|
12
|
+
@tests_metadata = tests_metadata
|
13
|
+
@test_reporter = test_reporter
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
@test_reporter.report_start_run
|
18
|
+
|
19
|
+
test_generator = Moto::Test::Generator.new
|
20
|
+
@tests_metadata.each do |metadata|
|
21
|
+
test_variants = test_generator.get_test_with_variants(metadata)
|
22
|
+
test_variants.each do |tc|
|
23
|
+
@test_reporter.report_start_test(tc.status, tc.metadata)
|
24
|
+
tc.status.initialize_run
|
25
|
+
tc.status.log_exception(Exceptions::TestSkipped.new('Dry run.'))
|
26
|
+
tc.status.finalize_run
|
27
|
+
@test_reporter.report_end_test(tc.status)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@test_reporter.report_end_run
|
32
|
+
|
33
|
+
# Exit application with code that represents status of test run
|
34
|
+
Kernel.exit(@test_reporter.run_status.bitmap)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require_relative '../../test/generator'
|
3
|
+
|
4
|
+
# Thread safe provider of test instances
|
5
|
+
|
6
|
+
module Moto
|
7
|
+
module Modes
|
8
|
+
module Run
|
9
|
+
class TestProvider
|
10
|
+
|
11
|
+
# @param [Array] tests_metadata
|
12
|
+
def initialize(tests_metadata)
|
13
|
+
super()
|
14
|
+
@test_repeats = Moto::Lib::Config.moto[:test_runner][:test_repeats]
|
15
|
+
@current_test_repeat = 1
|
16
|
+
@queue = Queue.new
|
17
|
+
@tests_metadata = tests_metadata
|
18
|
+
@test_generator = Moto::Test::Generator.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# Use this to retrieve tests safely in multithreaded environment
|
22
|
+
def get_test
|
23
|
+
create_tests
|
24
|
+
@queue.pop
|
25
|
+
end
|
26
|
+
|
27
|
+
# Pushes new tests to the queue if possible and the queue is already empty
|
28
|
+
def create_tests
|
29
|
+
if @queue.empty?
|
30
|
+
|
31
|
+
test_metadata = get_test_metadata
|
32
|
+
|
33
|
+
if test_metadata
|
34
|
+
test_variants = @test_generator.get_test_with_variants(test_metadata)
|
35
|
+
test_variants.each do |test|
|
36
|
+
@queue.push(test)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
private :create_tests
|
43
|
+
|
44
|
+
# Returns metadata of the test while supporting the number of repeats specified by the user
|
45
|
+
# return [Moto::Test::Metadata]
|
46
|
+
def get_test_metadata
|
47
|
+
|
48
|
+
if @current_test_repeat == 1
|
49
|
+
@test_metadata = @tests_metadata.shift
|
50
|
+
end
|
51
|
+
|
52
|
+
if @current_test_repeat == @test_repeats
|
53
|
+
@current_test_repeat = 1
|
54
|
+
else
|
55
|
+
@current_test_repeat += 1
|
56
|
+
end
|
57
|
+
|
58
|
+
@test_metadata
|
59
|
+
end
|
60
|
+
private :get_test_metadata
|
61
|
+
|
62
|
+
# Number of threads waiting for a job
|
63
|
+
def num_waiting
|
64
|
+
@queue.num_waiting
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative '../../reporting/test_reporter'
|
2
|
+
require_relative 'test_provider'
|
3
|
+
require_relative 'thread_context'
|
4
|
+
|
5
|
+
module Moto
|
6
|
+
module Modes
|
7
|
+
module Run
|
8
|
+
class TestRunner
|
9
|
+
|
10
|
+
attr_reader :test_reporter
|
11
|
+
|
12
|
+
# @param [Array] tests_metadata Collection of [Moto::Test::Metadata] objects describing Tests
|
13
|
+
# @param [Moto::Reporting::TestReporter] test_reporter Reporter of test/run statuses that communicates with external status listeners
|
14
|
+
# @param [Hash] stop_conditions Describe when TestRunner should abnormally stop its execution
|
15
|
+
# :error [Boolean]
|
16
|
+
# :fail [Boolean]
|
17
|
+
# :skip [Boolean]
|
18
|
+
def initialize(tests_metadata, test_reporter, stop_conditions)
|
19
|
+
@tests_metadata = tests_metadata
|
20
|
+
@test_reporter = test_reporter
|
21
|
+
@stop_conditions = stop_conditions
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
test_provider = TestProvider.new(@tests_metadata)
|
26
|
+
threads_max = Moto::Lib::Config.moto[:test_runner][:thread_count] || 1
|
27
|
+
|
28
|
+
# remove log/screenshot files from previous execution
|
29
|
+
@tests_metadata.each do |metadata|
|
30
|
+
FileUtils.rm_rf("#{File.dirname(metadata.test_path)}/logs")
|
31
|
+
end
|
32
|
+
|
33
|
+
@test_reporter.report_start_run
|
34
|
+
|
35
|
+
# Create as many threads as we're allowed by the config file.
|
36
|
+
# test_provider.get_test - will invoke Queue.pop thus putting the thread to sleep
|
37
|
+
# once there is no more work.
|
38
|
+
|
39
|
+
Thread.abort_on_exception = true
|
40
|
+
|
41
|
+
(1..threads_max).each do |index|
|
42
|
+
Thread.new do
|
43
|
+
Thread.current[:id] = index
|
44
|
+
loop do
|
45
|
+
tc = ThreadContext.new(test_provider.get_test, @test_reporter)
|
46
|
+
tc.run
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Waiting for all threads to run out of work so we can end the application
|
52
|
+
# or abonormal termination to be triggered based on options provided by the user
|
53
|
+
loop do
|
54
|
+
run_status = @test_reporter.run_status
|
55
|
+
if (test_provider.num_waiting == threads_max) ||
|
56
|
+
(@stop_conditions[:error] && run_status.tests_error.length > 0) ||
|
57
|
+
(@stop_conditions[:fail] && run_status.tests_failed.length > 0) ||
|
58
|
+
(@stop_conditions[:skip] && run_status.tests_skipped.length > 0)
|
59
|
+
break
|
60
|
+
end
|
61
|
+
|
62
|
+
sleep 2
|
63
|
+
end
|
64
|
+
|
65
|
+
@test_reporter.report_end_run
|
66
|
+
|
67
|
+
# Exit application with code that represents status of test run
|
68
|
+
Kernel.exit(@test_reporter.run_status.bitmap)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|