moto 0.0.14 → 0.0.15
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 +4 -4
- data/lib/cli.rb +105 -105
- data/lib/clients/website.rb +49 -47
- data/lib/listeners/webui.rb +70 -70
- data/lib/runner.rb +72 -72
- data/lib/test.rb +101 -101
- data/lib/test_generator.rb +68 -68
- data/lib/thread_context.rb +131 -128
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d372116a3d958f4b63271540b60d41d035f270e
|
4
|
+
data.tar.gz: c9aa807fd63cae0abe92f9103c1c44ea4f431235
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 274cc49288e9aaf523e23c64b9fd572d127c469f45213d234039e4fefc4cec598d97755e3208caea948cd2f24975b75dc74f857c18ae43f853b10422cd64eb1d
|
7
|
+
data.tar.gz: e101a87b1351073c09ac40cefc1fe76613a94783d25db13f2b4494c18756acce963d98f5639a429e2d684f83ce1139c0f81197958589e5b4b15bab75ad9c1a5a
|
data/lib/cli.rb
CHANGED
@@ -1,105 +1,105 @@
|
|
1
|
-
# TODO: fix this dumb verification of current working directory
|
2
|
-
unless File.exists? "#{Dir.pwd}/config/moto.rb"
|
3
|
-
puts 'Config file (config/moto.rb) not present.'
|
4
|
-
puts 'Does current working directory contain Moto application?'
|
5
|
-
exit 1
|
6
|
-
end
|
7
|
-
|
8
|
-
require 'logger'
|
9
|
-
require 'pp'
|
10
|
-
require 'yaml'
|
11
|
-
require 'active_support/inflector'
|
12
|
-
require 'active_support/core_ext/object/blank'
|
13
|
-
|
14
|
-
require 'bundler/setup'
|
15
|
-
Bundler.require
|
16
|
-
|
17
|
-
module MotoApp
|
18
|
-
DIR = Dir.pwd
|
19
|
-
end
|
20
|
-
|
21
|
-
module Moto
|
22
|
-
DIR = File.dirname(File.dirname(__FILE__))
|
23
|
-
end
|
24
|
-
|
25
|
-
require_relative './empty_listener'
|
26
|
-
require_relative './forward_context_methods'
|
27
|
-
require_relative './test_logging'
|
28
|
-
require_relative './runner_logging'
|
29
|
-
require_relative './runner'
|
30
|
-
require_relative './thread_context'
|
31
|
-
require_relative './result'
|
32
|
-
require_relative './assert'
|
33
|
-
require_relative './test'
|
34
|
-
require_relative './page'
|
35
|
-
require_relative './clients/base'
|
36
|
-
require_relative './listeners/base'
|
37
|
-
require_relative './listeners/console'
|
38
|
-
require_relative './listeners/console_dots'
|
39
|
-
require_relative './listeners/junit_xml'
|
40
|
-
require_relative './listeners/webui'
|
41
|
-
require_relative './test_generator'
|
42
|
-
require_relative './exceptions/moto'
|
43
|
-
require_relative './exceptions/test_skipped'
|
44
|
-
require_relative './exceptions/test_forced_failure'
|
45
|
-
require_relative './exceptions/test_forced_passed'
|
46
|
-
|
47
|
-
module Moto
|
48
|
-
|
49
|
-
class Cli
|
50
|
-
def self.run(argv)
|
51
|
-
test_paths_absolute = []
|
52
|
-
test_classes = []
|
53
|
-
|
54
|
-
unless argv[ :tests ].nil?
|
55
|
-
argv[ :tests ].each do |dir_name|
|
56
|
-
test_paths = Dir.glob("#{MotoApp::DIR}/tests/#{dir_name}/**/*.rb")
|
57
|
-
test_paths -= test_paths_absolute
|
58
|
-
test_paths_absolute += test_paths
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# TODO Optimization for files without #MOTO_TAGS
|
63
|
-
unless argv[ :tags ].nil?
|
64
|
-
tests_total = Dir.glob("#{MotoApp::DIR}/tests/**/*.rb")
|
65
|
-
argv[ :tags ].each do |tag_name|
|
66
|
-
tests_total.each do |test_dir|
|
67
|
-
test_body = File.read(test_dir)
|
68
|
-
test_body.each_line do |line|
|
69
|
-
line = line.delete(' ')
|
70
|
-
if line.include?( '#MOTO_TAGS')
|
71
|
-
if line.include?(tag_name + ',')
|
72
|
-
test_paths_absolute.include?(test_dir) || test_paths_absolute << test_dir
|
73
|
-
break
|
74
|
-
else
|
75
|
-
break
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
#TODO Display criteria used
|
84
|
-
if test_paths_absolute.empty?
|
85
|
-
puts 'No tests found for given arguments'
|
86
|
-
exit 1
|
87
|
-
end
|
88
|
-
|
89
|
-
tg = TestGenerator.new(MotoApp::DIR)
|
90
|
-
test_paths_absolute.each do |test_path|
|
91
|
-
test_classes << tg.generate(test_path)
|
92
|
-
end
|
93
|
-
|
94
|
-
listeners = []
|
95
|
-
argv[ :reporters ].each do |r|
|
96
|
-
listener = 'Moto::Listeners::' + r.camelize
|
97
|
-
listeners << listener.constantize
|
98
|
-
end
|
99
|
-
|
100
|
-
runner = Moto::Runner.new(test_classes, listeners, argv[:environments], argv[:config], argv[:name])
|
101
|
-
runner.run
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|
1
|
+
# TODO: fix this dumb verification of current working directory
|
2
|
+
unless File.exists? "#{Dir.pwd}/config/moto.rb"
|
3
|
+
puts 'Config file (config/moto.rb) not present.'
|
4
|
+
puts 'Does current working directory contain Moto application?'
|
5
|
+
exit 1
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'logger'
|
9
|
+
require 'pp'
|
10
|
+
require 'yaml'
|
11
|
+
require 'active_support/inflector'
|
12
|
+
require 'active_support/core_ext/object/blank'
|
13
|
+
|
14
|
+
require 'bundler/setup'
|
15
|
+
Bundler.require
|
16
|
+
|
17
|
+
module MotoApp
|
18
|
+
DIR = Dir.pwd
|
19
|
+
end
|
20
|
+
|
21
|
+
module Moto
|
22
|
+
DIR = File.dirname(File.dirname(__FILE__))
|
23
|
+
end
|
24
|
+
|
25
|
+
require_relative './empty_listener'
|
26
|
+
require_relative './forward_context_methods'
|
27
|
+
require_relative './test_logging'
|
28
|
+
require_relative './runner_logging'
|
29
|
+
require_relative './runner'
|
30
|
+
require_relative './thread_context'
|
31
|
+
require_relative './result'
|
32
|
+
require_relative './assert'
|
33
|
+
require_relative './test'
|
34
|
+
require_relative './page'
|
35
|
+
require_relative './clients/base'
|
36
|
+
require_relative './listeners/base'
|
37
|
+
require_relative './listeners/console'
|
38
|
+
require_relative './listeners/console_dots'
|
39
|
+
require_relative './listeners/junit_xml'
|
40
|
+
require_relative './listeners/webui'
|
41
|
+
require_relative './test_generator'
|
42
|
+
require_relative './exceptions/moto'
|
43
|
+
require_relative './exceptions/test_skipped'
|
44
|
+
require_relative './exceptions/test_forced_failure'
|
45
|
+
require_relative './exceptions/test_forced_passed'
|
46
|
+
|
47
|
+
module Moto
|
48
|
+
|
49
|
+
class Cli
|
50
|
+
def self.run(argv)
|
51
|
+
test_paths_absolute = []
|
52
|
+
test_classes = []
|
53
|
+
|
54
|
+
unless argv[ :tests ].nil?
|
55
|
+
argv[ :tests ].each do |dir_name|
|
56
|
+
test_paths = Dir.glob("#{MotoApp::DIR}/tests/#{dir_name}/**/*.rb")
|
57
|
+
test_paths -= test_paths_absolute
|
58
|
+
test_paths_absolute += test_paths
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO Optimization for files without #MOTO_TAGS
|
63
|
+
unless argv[ :tags ].nil?
|
64
|
+
tests_total = Dir.glob("#{MotoApp::DIR}/tests/**/*.rb")
|
65
|
+
argv[ :tags ].each do |tag_name|
|
66
|
+
tests_total.each do |test_dir|
|
67
|
+
test_body = File.read(test_dir)
|
68
|
+
test_body.each_line do |line|
|
69
|
+
line = line.delete(' ')
|
70
|
+
if line.include?( '#MOTO_TAGS')
|
71
|
+
if line.include?(tag_name + ',')
|
72
|
+
test_paths_absolute.include?(test_dir) || test_paths_absolute << test_dir
|
73
|
+
break
|
74
|
+
else
|
75
|
+
break
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#TODO Display criteria used
|
84
|
+
if test_paths_absolute.empty?
|
85
|
+
puts 'No tests found for given arguments'
|
86
|
+
exit 1
|
87
|
+
end
|
88
|
+
|
89
|
+
tg = TestGenerator.new(MotoApp::DIR)
|
90
|
+
test_paths_absolute.each do |test_path|
|
91
|
+
test_classes << tg.generate(test_path)
|
92
|
+
end
|
93
|
+
|
94
|
+
listeners = []
|
95
|
+
argv[ :reporters ].each do |r|
|
96
|
+
listener = 'Moto::Listeners::' + r.camelize
|
97
|
+
listeners << listener.constantize
|
98
|
+
end
|
99
|
+
|
100
|
+
runner = Moto::Runner.new(test_classes, listeners, argv[:environments], argv[:config], argv[:name])
|
101
|
+
runner.run
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
data/lib/clients/website.rb
CHANGED
@@ -1,47 +1,49 @@
|
|
1
|
-
require 'capybara'
|
2
|
-
|
3
|
-
module Moto
|
4
|
-
module Clients
|
5
|
-
|
6
|
-
class Website < Moto::Clients::Base
|
7
|
-
|
8
|
-
attr_reader :session
|
9
|
-
|
10
|
-
ignore_logging(:page)
|
11
|
-
ignore_logging(:context)
|
12
|
-
ignore_logging(:session)
|
13
|
-
|
14
|
-
def start_run
|
15
|
-
# TODO: make session driver configurable
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
1
|
+
require 'capybara'
|
2
|
+
|
3
|
+
module Moto
|
4
|
+
module Clients
|
5
|
+
|
6
|
+
class Website < Moto::Clients::Base
|
7
|
+
|
8
|
+
attr_reader :session
|
9
|
+
|
10
|
+
ignore_logging(:page)
|
11
|
+
ignore_logging(:context)
|
12
|
+
ignore_logging(:session)
|
13
|
+
|
14
|
+
def start_run
|
15
|
+
# TODO: make session driver configurable
|
16
|
+
context.runner.my_config[:capybara][:default_selector] &&
|
17
|
+
Capybara.default_selector = context.runner.my_config[:capybara][:default_selector]
|
18
|
+
@session = Capybara::Session.new(context.runner.my_config[:capybara][:default_driver])
|
19
|
+
@pages = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def end_run
|
23
|
+
@session.driver.browser.close # TODO: check that it really works
|
24
|
+
end
|
25
|
+
|
26
|
+
def start_test(test)
|
27
|
+
# @context.current_test.logger.info("Hi mom, I'm opening some pages!")
|
28
|
+
@session.reset_session!
|
29
|
+
end
|
30
|
+
|
31
|
+
def end_test(test)
|
32
|
+
@session.reset_session!
|
33
|
+
end
|
34
|
+
|
35
|
+
def page(p)
|
36
|
+
page_class_name = "#{self.class.name}::Pages::#{p}"
|
37
|
+
page_class_name.gsub!('Moto::', 'MotoApp::')
|
38
|
+
if @pages[page_class_name].nil?
|
39
|
+
a = page_class_name.underscore.split('/')
|
40
|
+
page_path = a[1..20].join('/')
|
41
|
+
require "#{MotoApp::DIR}/lib/#{page_path}"
|
42
|
+
@pages[page_class_name] = page_class_name.constantize.new(self)
|
43
|
+
end
|
44
|
+
@pages[page_class_name]
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/listeners/webui.rb
CHANGED
@@ -1,71 +1,71 @@
|
|
1
|
-
require 'rest-client'
|
2
|
-
require 'sys/uname'
|
3
|
-
|
4
|
-
module Moto
|
5
|
-
module Listeners
|
6
|
-
class Webui < Base
|
7
|
-
|
8
|
-
def start_run
|
9
|
-
# POST http://sandbox.dev:3000/api/runs/create
|
10
|
-
@url = @runner.my_config[:url]
|
11
|
-
data = {
|
12
|
-
name: @runner.name,
|
13
|
-
result: Moto::Result::RUNNING,
|
14
|
-
cnt_all: nil,
|
15
|
-
cnt_passed: nil,
|
16
|
-
cnt_failure: nil,
|
17
|
-
cnt_error: nil,
|
18
|
-
cnt_skipped: nil,
|
19
|
-
user: Sys::Uname.sysname.downcase.include?('windows') ? ENV['USERNAME'] : ENV['LOGNAME'],
|
20
|
-
host: Sys::Uname.nodename,
|
21
|
-
pid: Process.pid
|
22
|
-
}
|
23
|
-
@run = JSON.parse( RestClient.post( "#{@url}/api/runs", data.to_json, :content_type => :json, :accept => :json ) )
|
24
|
-
@tests = {}
|
25
|
-
end
|
26
|
-
|
27
|
-
def end_run
|
28
|
-
# PUT http://sandbox.dev:3000/api/runs/1
|
29
|
-
data = {
|
30
|
-
result: @runner.result.summary[:result],
|
31
|
-
cnt_all: @runner.result.summary[:cnt_all],
|
32
|
-
cnt_passed: @runner.result.summary[:cnt_passed],
|
33
|
-
cnt_failure: @runner.result.summary[:cnt_failure],
|
34
|
-
cnt_error: @runner.result.summary[:cnt_error],
|
35
|
-
cnt_skipped: @runner.result.summary[:cnt_skipped],
|
36
|
-
duration: @runner.result.summary[:duration]
|
37
|
-
}
|
38
|
-
@run = JSON.parse( RestClient.put( "#{@url}/api/runs/#{@run['id']}", data.to_json, :content_type => :json, :accept => :json ) )
|
39
|
-
end
|
40
|
-
|
41
|
-
def start_test(test)
|
42
|
-
# POST http://sandbox.dev:3000/api/tests/create
|
43
|
-
data = {
|
44
|
-
name: test.name,
|
45
|
-
class_name: test.class.name,
|
46
|
-
log: nil,
|
47
|
-
run_id: @run['id'],
|
48
|
-
env: test.env,
|
49
|
-
parameters: test.params.to_s,
|
50
|
-
result: Moto::Result::RUNNING,
|
51
|
-
error: nil,
|
52
|
-
failures: nil,
|
53
|
-
}
|
54
|
-
@tests[test.name] = JSON.parse( RestClient.post( "#{@url}/api/tests", data.to_json, :content_type => :json, :accept => :json ) )
|
55
|
-
end
|
56
|
-
|
57
|
-
def end_test(test)
|
58
|
-
log = File.read(test.log_path)
|
59
|
-
data = {
|
60
|
-
log: log,
|
61
|
-
result: @runner.result[test.name][:result],
|
62
|
-
error: @runner.result[test.name][:error].nil? ? nil : @runner.result[test.name][:error].message,
|
63
|
-
failures: @runner.result[test.name][:failures].join("\n\t"),
|
64
|
-
duration: @runner.result[test.name][:duration]
|
65
|
-
}
|
66
|
-
@tests[test.name] = JSON.parse( RestClient.put( "#{@url}/api/tests/#{@tests[test.name]['id']}", data.to_json, :content_type => :json, :accept => :json ) )
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
70
|
-
end
|
1
|
+
require 'rest-client'
|
2
|
+
require 'sys/uname'
|
3
|
+
|
4
|
+
module Moto
|
5
|
+
module Listeners
|
6
|
+
class Webui < Base
|
7
|
+
|
8
|
+
def start_run
|
9
|
+
# POST http://sandbox.dev:3000/api/runs/create
|
10
|
+
@url = @runner.my_config[:url]
|
11
|
+
data = {
|
12
|
+
name: @runner.name,
|
13
|
+
result: Moto::Result::RUNNING,
|
14
|
+
cnt_all: nil,
|
15
|
+
cnt_passed: nil,
|
16
|
+
cnt_failure: nil,
|
17
|
+
cnt_error: nil,
|
18
|
+
cnt_skipped: nil,
|
19
|
+
user: Sys::Uname.sysname.downcase.include?('windows') ? ENV['USERNAME'] : ENV['LOGNAME'],
|
20
|
+
host: Sys::Uname.nodename,
|
21
|
+
pid: Process.pid
|
22
|
+
}
|
23
|
+
@run = JSON.parse( RestClient.post( "#{@url}/api/runs", data.to_json, :content_type => :json, :accept => :json ) )
|
24
|
+
@tests = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_run
|
28
|
+
# PUT http://sandbox.dev:3000/api/runs/1
|
29
|
+
data = {
|
30
|
+
result: @runner.result.summary[:result],
|
31
|
+
cnt_all: @runner.result.summary[:cnt_all],
|
32
|
+
cnt_passed: @runner.result.summary[:cnt_passed],
|
33
|
+
cnt_failure: @runner.result.summary[:cnt_failure],
|
34
|
+
cnt_error: @runner.result.summary[:cnt_error],
|
35
|
+
cnt_skipped: @runner.result.summary[:cnt_skipped],
|
36
|
+
duration: @runner.result.summary[:duration]
|
37
|
+
}
|
38
|
+
@run = JSON.parse( RestClient.put( "#{@url}/api/runs/#{@run['id']}", data.to_json, :content_type => :json, :accept => :json ) )
|
39
|
+
end
|
40
|
+
|
41
|
+
def start_test(test)
|
42
|
+
# POST http://sandbox.dev:3000/api/tests/create
|
43
|
+
data = {
|
44
|
+
name: test.name,
|
45
|
+
class_name: test.class.name,
|
46
|
+
log: nil,
|
47
|
+
run_id: @run['id'],
|
48
|
+
env: test.env,
|
49
|
+
parameters: test.params.to_s,
|
50
|
+
result: Moto::Result::RUNNING,
|
51
|
+
error: nil,
|
52
|
+
failures: nil,
|
53
|
+
}
|
54
|
+
@tests[test.name] = JSON.parse( RestClient.post( "#{@url}/api/tests", data.to_json, :content_type => :json, :accept => :json ) )
|
55
|
+
end
|
56
|
+
|
57
|
+
def end_test(test)
|
58
|
+
log = File.read(test.log_path)
|
59
|
+
data = {
|
60
|
+
log: log,
|
61
|
+
result: @runner.result[test.name][:result],
|
62
|
+
error: @runner.result[test.name][:error].nil? ? nil : @runner.result[test.name][:error].message,
|
63
|
+
failures: @runner.result[test.name][:failures].join("\n\t"),
|
64
|
+
duration: @runner.result[test.name][:duration]
|
65
|
+
}
|
66
|
+
@tests[test.name] = JSON.parse( RestClient.put( "#{@url}/api/tests/#{@tests[test.name]['id']}", data.to_json, :content_type => :json, :accept => :json ) )
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
71
|
end
|
data/lib/runner.rb
CHANGED
@@ -1,73 +1,73 @@
|
|
1
|
-
module Moto
|
2
|
-
class Runner
|
3
|
-
|
4
|
-
attr_reader :result
|
5
|
-
attr_reader :listeners
|
6
|
-
attr_reader :logger
|
7
|
-
attr_reader :environments
|
8
|
-
attr_reader :assert
|
9
|
-
attr_reader :config
|
10
|
-
attr_reader :name
|
11
|
-
|
12
|
-
def initialize(tests, listeners, environments, config, name)
|
13
|
-
@tests = tests
|
14
|
-
@config = config
|
15
|
-
@threads = []
|
16
|
-
@name = name
|
17
|
-
|
18
|
-
# TODO: initialize logger from config (yml or just ruby code)
|
19
|
-
# @logger = Logger.new(STDOUT)
|
20
|
-
@logger = Logger.new(File.open("#{MotoApp::DIR}/moto.log", File::WRONLY | File::APPEND | File::CREAT))
|
21
|
-
# @logger.level = Logger::WARN
|
22
|
-
|
23
|
-
@result = Result.new(self)
|
24
|
-
|
25
|
-
# TODO: validate envs, maybe no-env should be supported as well?
|
26
|
-
environments << :__default if environments.empty?
|
27
|
-
@environments = environments
|
28
|
-
|
29
|
-
@listeners = []
|
30
|
-
if listeners.empty?
|
31
|
-
my_config[:default_listeners].each do |l|
|
32
|
-
@listeners << l.new(self)
|
33
|
-
end
|
34
|
-
else
|
35
|
-
listeners.each do |l|
|
36
|
-
@listeners << l.new(self)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
@listeners.unshift(@result)
|
40
|
-
end
|
41
|
-
|
42
|
-
def my_config
|
43
|
-
caller_path = caller.first.to_s.split(/:\d/)[0]
|
44
|
-
keys = []
|
45
|
-
if caller_path.include? MotoApp::DIR
|
46
|
-
caller_path.sub!( "#{MotoApp::DIR}/lib/", '' )
|
47
|
-
keys << 'moto_app'
|
48
|
-
elsif caller_path.include? Moto::DIR
|
49
|
-
caller_path.sub!( "#{Moto::DIR}/lib/", '' )
|
50
|
-
keys << 'moto'
|
51
|
-
end
|
52
|
-
caller_path.sub!('.rb', '')
|
53
|
-
keys << caller_path.split('/')
|
54
|
-
keys.flatten!
|
55
|
-
eval "@config#{keys.map{|k| "[:#{k}]" }.join('')}"
|
56
|
-
end
|
57
|
-
|
58
|
-
# TODO: assigning tests to threads dynamically
|
59
|
-
def run
|
60
|
-
@listeners.each { |l| l.start_run }
|
61
|
-
test_slices = @tests.each_slice((@tests.size.to_f/my_config[:thread_count]).ceil).to_a
|
62
|
-
test_slices.each do |slice|
|
63
|
-
@threads << Thread.new do
|
64
|
-
tc = ThreadContext.new(self, slice)
|
65
|
-
tc.run
|
66
|
-
end
|
67
|
-
end
|
68
|
-
@threads.each{ |t| t.join }
|
69
|
-
@listeners.each { |l| l.end_run }
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
1
|
+
module Moto
|
2
|
+
class Runner
|
3
|
+
|
4
|
+
attr_reader :result
|
5
|
+
attr_reader :listeners
|
6
|
+
attr_reader :logger
|
7
|
+
attr_reader :environments
|
8
|
+
attr_reader :assert
|
9
|
+
attr_reader :config
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(tests, listeners, environments, config, name)
|
13
|
+
@tests = tests
|
14
|
+
@config = config
|
15
|
+
@threads = []
|
16
|
+
@name = name
|
17
|
+
|
18
|
+
# TODO: initialize logger from config (yml or just ruby code)
|
19
|
+
# @logger = Logger.new(STDOUT)
|
20
|
+
@logger = Logger.new(File.open("#{MotoApp::DIR}/moto.log", File::WRONLY | File::APPEND | File::CREAT))
|
21
|
+
# @logger.level = Logger::WARN
|
22
|
+
|
23
|
+
@result = Result.new(self)
|
24
|
+
|
25
|
+
# TODO: validate envs, maybe no-env should be supported as well?
|
26
|
+
environments << :__default if environments.empty?
|
27
|
+
@environments = environments
|
28
|
+
|
29
|
+
@listeners = []
|
30
|
+
if listeners.empty?
|
31
|
+
my_config[:default_listeners].each do |l|
|
32
|
+
@listeners << l.new(self)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
listeners.each do |l|
|
36
|
+
@listeners << l.new(self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@listeners.unshift(@result)
|
40
|
+
end
|
41
|
+
|
42
|
+
def my_config
|
43
|
+
caller_path = caller.first.to_s.split(/:\d/)[0]
|
44
|
+
keys = []
|
45
|
+
if caller_path.include? MotoApp::DIR
|
46
|
+
caller_path.sub!( "#{MotoApp::DIR}/lib/", '' )
|
47
|
+
keys << 'moto_app'
|
48
|
+
elsif caller_path.include? Moto::DIR
|
49
|
+
caller_path.sub!( "#{Moto::DIR}/lib/", '' )
|
50
|
+
keys << 'moto'
|
51
|
+
end
|
52
|
+
caller_path.sub!('.rb', '')
|
53
|
+
keys << caller_path.split('/')
|
54
|
+
keys.flatten!
|
55
|
+
eval "@config#{keys.map{|k| "[:#{k}]" }.join('')}"
|
56
|
+
end
|
57
|
+
|
58
|
+
# TODO: assigning tests to threads dynamically
|
59
|
+
def run
|
60
|
+
@listeners.each { |l| l.start_run }
|
61
|
+
test_slices = @tests.each_slice((@tests.size.to_f/my_config[:thread_count]).ceil).to_a
|
62
|
+
test_slices.each do |slice|
|
63
|
+
@threads << Thread.new do
|
64
|
+
tc = ThreadContext.new(self, slice)
|
65
|
+
tc.run
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@threads.each{ |t| t.join }
|
69
|
+
@listeners.each { |l| l.end_run }
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
73
|
end
|
data/lib/test.rb
CHANGED
@@ -1,102 +1,102 @@
|
|
1
|
-
module Moto
|
2
|
-
class Test
|
3
|
-
|
4
|
-
include Moto::Assert
|
5
|
-
include Moto::ForwardContextMethods
|
6
|
-
|
7
|
-
attr_writer :context
|
8
|
-
attr_accessor :result
|
9
|
-
attr_reader :name
|
10
|
-
attr_reader :env
|
11
|
-
attr_reader :params
|
12
|
-
attr_writer :static_path
|
13
|
-
attr_accessor :log_path
|
14
|
-
|
15
|
-
class << self
|
16
|
-
attr_accessor :_path
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.inherited(k)
|
20
|
-
k._path = caller.first.match( /(.+):\d+:in/ )[1]
|
21
|
-
end
|
22
|
-
|
23
|
-
def path
|
24
|
-
self.class._path
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize
|
28
|
-
# @context = context
|
29
|
-
@result = Moto::Result::PENDING
|
30
|
-
end
|
31
|
-
|
32
|
-
def init(env, params, params_index)
|
33
|
-
@env = env
|
34
|
-
@params = params
|
35
|
-
set_name(params_index)
|
36
|
-
end
|
37
|
-
|
38
|
-
def set_name(params_index)
|
39
|
-
if @env == :__default
|
40
|
-
return @name = "#{self.class.to_s}" if @params.empty?
|
41
|
-
return @name = "#{self.class.to_s}/#{@params['__name']}" if @params.key?('__name')
|
42
|
-
return @name = "#{self.class.to_s}/params_#{params_index}" unless @params.key?('__name')
|
43
|
-
else
|
44
|
-
return @name = "#{self.class.to_s}/#{@env}" if @params.empty?
|
45
|
-
return @name = "#{self.class.to_s}/#{@env}/#{@params['__name']}" if @params.key?('__name')
|
46
|
-
return @name = "#{self.class.to_s}/#{@env}/params_#{params_index}" unless @params.key?('__name')
|
47
|
-
end
|
48
|
-
@name = self.class.to_s
|
49
|
-
end
|
50
|
-
|
51
|
-
def dir
|
52
|
-
# puts self.class.path
|
53
|
-
return File.dirname(@static_path) unless @static_path.nil?
|
54
|
-
File.dirname(self.path)
|
55
|
-
end
|
56
|
-
|
57
|
-
def filename
|
58
|
-
return File.basename(@static_path, ".*") unless @static_path.nil?
|
59
|
-
File.basename(path, ".*")
|
60
|
-
end
|
61
|
-
|
62
|
-
def run
|
63
|
-
# abstract
|
64
|
-
end
|
65
|
-
|
66
|
-
def before
|
67
|
-
# abstract
|
68
|
-
end
|
69
|
-
|
70
|
-
def after
|
71
|
-
# abstract
|
72
|
-
end
|
73
|
-
|
74
|
-
def skip(msg = nil)
|
75
|
-
if msg.nil?
|
76
|
-
msg = "Test skipped with no reason given."
|
77
|
-
else
|
78
|
-
msg = "Skip reason: #{msg}"
|
79
|
-
end
|
80
|
-
raise Exceptions::TestSkipped.new msg
|
81
|
-
end
|
82
|
-
|
83
|
-
def fail(msg = nil)
|
84
|
-
if msg.nil?
|
85
|
-
msg = "Test forcibly failed with no reason given."
|
86
|
-
else
|
87
|
-
msg = "Forced failure, reason: #{msg}"
|
88
|
-
end
|
89
|
-
raise Exceptions::TestForcedFailure.new msg
|
90
|
-
end
|
91
|
-
|
92
|
-
def pass(msg = nil)
|
93
|
-
if msg.nil?
|
94
|
-
msg = "Test forcibly passed with no reason given."
|
95
|
-
else
|
96
|
-
msg = "Forced passed, reason: #{msg}"
|
97
|
-
end
|
98
|
-
raise Exceptions::TestForcedPassed.new msg
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
1
|
+
module Moto
|
2
|
+
class Test
|
3
|
+
|
4
|
+
include Moto::Assert
|
5
|
+
include Moto::ForwardContextMethods
|
6
|
+
|
7
|
+
attr_writer :context
|
8
|
+
attr_accessor :result
|
9
|
+
attr_reader :name
|
10
|
+
attr_reader :env
|
11
|
+
attr_reader :params
|
12
|
+
attr_writer :static_path
|
13
|
+
attr_accessor :log_path
|
14
|
+
|
15
|
+
class << self
|
16
|
+
attr_accessor :_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.inherited(k)
|
20
|
+
k._path = caller.first.match( /(.+):\d+:in/ )[1]
|
21
|
+
end
|
22
|
+
|
23
|
+
def path
|
24
|
+
self.class._path
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
# @context = context
|
29
|
+
@result = Moto::Result::PENDING
|
30
|
+
end
|
31
|
+
|
32
|
+
def init(env, params, params_index)
|
33
|
+
@env = env
|
34
|
+
@params = params
|
35
|
+
set_name(params_index)
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_name(params_index)
|
39
|
+
if @env == :__default
|
40
|
+
return @name = "#{self.class.to_s}" if @params.empty?
|
41
|
+
return @name = "#{self.class.to_s}/#{@params['__name']}" if @params.key?('__name')
|
42
|
+
return @name = "#{self.class.to_s}/params_#{params_index}" unless @params.key?('__name')
|
43
|
+
else
|
44
|
+
return @name = "#{self.class.to_s}/#{@env}" if @params.empty?
|
45
|
+
return @name = "#{self.class.to_s}/#{@env}/#{@params['__name']}" if @params.key?('__name')
|
46
|
+
return @name = "#{self.class.to_s}/#{@env}/params_#{params_index}" unless @params.key?('__name')
|
47
|
+
end
|
48
|
+
@name = self.class.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def dir
|
52
|
+
# puts self.class.path
|
53
|
+
return File.dirname(@static_path) unless @static_path.nil?
|
54
|
+
File.dirname(self.path)
|
55
|
+
end
|
56
|
+
|
57
|
+
def filename
|
58
|
+
return File.basename(@static_path, ".*") unless @static_path.nil?
|
59
|
+
File.basename(path, ".*")
|
60
|
+
end
|
61
|
+
|
62
|
+
def run
|
63
|
+
# abstract
|
64
|
+
end
|
65
|
+
|
66
|
+
def before
|
67
|
+
# abstract
|
68
|
+
end
|
69
|
+
|
70
|
+
def after
|
71
|
+
# abstract
|
72
|
+
end
|
73
|
+
|
74
|
+
def skip(msg = nil)
|
75
|
+
if msg.nil?
|
76
|
+
msg = "Test skipped with no reason given."
|
77
|
+
else
|
78
|
+
msg = "Skip reason: #{msg}"
|
79
|
+
end
|
80
|
+
raise Exceptions::TestSkipped.new msg
|
81
|
+
end
|
82
|
+
|
83
|
+
def fail(msg = nil)
|
84
|
+
if msg.nil?
|
85
|
+
msg = "Test forcibly failed with no reason given."
|
86
|
+
else
|
87
|
+
msg = "Forced failure, reason: #{msg}"
|
88
|
+
end
|
89
|
+
raise Exceptions::TestForcedFailure.new msg
|
90
|
+
end
|
91
|
+
|
92
|
+
def pass(msg = nil)
|
93
|
+
if msg.nil?
|
94
|
+
msg = "Test forcibly passed with no reason given."
|
95
|
+
else
|
96
|
+
msg = "Forced passed, reason: #{msg}"
|
97
|
+
end
|
98
|
+
raise Exceptions::TestForcedPassed.new msg
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
102
|
end
|
data/lib/test_generator.rb
CHANGED
@@ -1,69 +1,69 @@
|
|
1
|
-
module MotoApp
|
2
|
-
module Tests
|
3
|
-
end
|
4
|
-
end
|
5
|
-
|
6
|
-
module Moto
|
7
|
-
class TestGenerator
|
8
|
-
|
9
|
-
def initialize(app_dir)
|
10
|
-
@app_dir = app_dir
|
11
|
-
end
|
12
|
-
|
13
|
-
# assuming that target file includes full valid ruby class
|
14
|
-
def create(class_name)
|
15
|
-
class_name = 'MotoApp::Tests::'+class_name
|
16
|
-
a = class_name.underscore.split('/')
|
17
|
-
test_path = (a[1..20]+[a[-1]]).join('/')
|
18
|
-
|
19
|
-
# TODO: check if this path and constant exists
|
20
|
-
require "#{MotoApp::DIR}/#{test_path}"
|
21
|
-
test_const = class_name.safe_constantize
|
22
|
-
test_const.new
|
23
|
-
end
|
24
|
-
|
25
|
-
def create_module_tree(root_module, next_modules)
|
26
|
-
next_module_name = next_modules.shift
|
27
|
-
if root_module.const_defined?(next_module_name.to_sym)
|
28
|
-
m = root_module.const_get(next_module_name.to_sym)
|
29
|
-
else
|
30
|
-
m = Module.new
|
31
|
-
root_module.const_set(next_module_name.to_sym, m)
|
32
|
-
end
|
33
|
-
return m if next_modules.empty?
|
34
|
-
create_module_tree(m, next_modules)
|
35
|
-
end
|
36
|
-
|
37
|
-
# assuming that target file includes only content of method 'run' and some magic comments
|
38
|
-
def generate(test_path_absolute)
|
39
|
-
method_body = File.read(test_path_absolute) + "\n"
|
40
|
-
|
41
|
-
base = Moto::Test
|
42
|
-
base_class_string = method_body.match( /^#\s*BASE_CLASS:\s(\S+)/ )
|
43
|
-
unless base_class_string.nil?
|
44
|
-
base_class_string = base_class_string[1].strip
|
45
|
-
|
46
|
-
a = base_class_string.underscore.split('/')
|
47
|
-
base_test_path = a[1..-1].join('/')
|
48
|
-
|
49
|
-
require "#{MotoApp::DIR}/lib/#{base_test_path}"
|
50
|
-
base = base_class_string.constantize
|
51
|
-
end
|
52
|
-
|
53
|
-
# MotoApp::Tests::Login::Short
|
54
|
-
consts = test_path_absolute.camelize.split('Tests::')[1].split('::')
|
55
|
-
consts.pop
|
56
|
-
class_name = consts.pop
|
57
|
-
|
58
|
-
m = create_module_tree(MotoApp::Tests, consts)
|
59
|
-
cls = Class.new(base)
|
60
|
-
m.const_set(class_name.to_sym, cls)
|
61
|
-
|
62
|
-
test_object = cls.new
|
63
|
-
test_object.instance_eval( "def run\n #{method_body} \n end" )
|
64
|
-
test_object.static_path = test_path_absolute
|
65
|
-
test_object
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
1
|
+
module MotoApp
|
2
|
+
module Tests
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
module Moto
|
7
|
+
class TestGenerator
|
8
|
+
|
9
|
+
def initialize(app_dir)
|
10
|
+
@app_dir = app_dir
|
11
|
+
end
|
12
|
+
|
13
|
+
# assuming that target file includes full valid ruby class
|
14
|
+
def create(class_name)
|
15
|
+
class_name = 'MotoApp::Tests::'+class_name
|
16
|
+
a = class_name.underscore.split('/')
|
17
|
+
test_path = (a[1..20]+[a[-1]]).join('/')
|
18
|
+
|
19
|
+
# TODO: check if this path and constant exists
|
20
|
+
require "#{MotoApp::DIR}/#{test_path}"
|
21
|
+
test_const = class_name.safe_constantize
|
22
|
+
test_const.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_module_tree(root_module, next_modules)
|
26
|
+
next_module_name = next_modules.shift
|
27
|
+
if root_module.const_defined?(next_module_name.to_sym)
|
28
|
+
m = root_module.const_get(next_module_name.to_sym)
|
29
|
+
else
|
30
|
+
m = Module.new
|
31
|
+
root_module.const_set(next_module_name.to_sym, m)
|
32
|
+
end
|
33
|
+
return m if next_modules.empty?
|
34
|
+
create_module_tree(m, next_modules)
|
35
|
+
end
|
36
|
+
|
37
|
+
# assuming that target file includes only content of method 'run' and some magic comments
|
38
|
+
def generate(test_path_absolute)
|
39
|
+
method_body = File.read(test_path_absolute) + "\n"
|
40
|
+
|
41
|
+
base = Moto::Test
|
42
|
+
base_class_string = method_body.match( /^#\s*BASE_CLASS:\s(\S+)/ )
|
43
|
+
unless base_class_string.nil?
|
44
|
+
base_class_string = base_class_string[1].strip
|
45
|
+
|
46
|
+
a = base_class_string.underscore.split('/')
|
47
|
+
base_test_path = a[1..-1].join('/')
|
48
|
+
|
49
|
+
require "#{MotoApp::DIR}/lib/#{base_test_path}"
|
50
|
+
base = base_class_string.constantize
|
51
|
+
end
|
52
|
+
|
53
|
+
# MotoApp::Tests::Login::Short
|
54
|
+
consts = test_path_absolute.camelize.split('Tests::')[1].split('::')
|
55
|
+
consts.pop
|
56
|
+
class_name = consts.pop
|
57
|
+
|
58
|
+
m = create_module_tree(MotoApp::Tests, consts)
|
59
|
+
cls = Class.new(base)
|
60
|
+
m.const_set(class_name.to_sym, cls)
|
61
|
+
|
62
|
+
test_object = cls.new
|
63
|
+
test_object.instance_eval( "def run\n #{method_body} \n end" )
|
64
|
+
test_object.static_path = test_path_absolute
|
65
|
+
test_object
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
69
|
end
|
data/lib/thread_context.rb
CHANGED
@@ -1,129 +1,132 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
attr_reader :
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@
|
14
|
-
@tests
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
instance.
|
52
|
-
instance.
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
"@config['#{
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
raise
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
params_all.
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
# TODO:
|
97
|
-
|
98
|
-
@
|
99
|
-
|
100
|
-
@
|
101
|
-
test
|
102
|
-
@
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
rescue
|
109
|
-
|
110
|
-
@
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
@
|
118
|
-
|
119
|
-
@runner.listeners
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Moto
|
4
|
+
class ThreadContext
|
5
|
+
|
6
|
+
# all resources specific for single thread will be initialized here. E.g. browser session
|
7
|
+
attr_reader :runner
|
8
|
+
attr_reader :logger
|
9
|
+
# attr_reader :log_path
|
10
|
+
attr_reader :current_test
|
11
|
+
|
12
|
+
def initialize(runner, tests)
|
13
|
+
@runner = runner
|
14
|
+
@tests = tests
|
15
|
+
@clients = {}
|
16
|
+
@tests.each do |t|
|
17
|
+
t.context = self
|
18
|
+
end
|
19
|
+
@config = {}
|
20
|
+
Dir.glob("config/*.yml").each do |f|
|
21
|
+
@config.deep_merge! YAML.load_file(f)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def client(name)
|
26
|
+
return @clients[name] if @clients.key? name
|
27
|
+
|
28
|
+
name_app = 'MotoApp::Clients::' + name
|
29
|
+
name_moto = 'Moto::Clients::' + name
|
30
|
+
|
31
|
+
c = try_client(name_app, "#{MotoApp::DIR}/lib")
|
32
|
+
unless c.nil?
|
33
|
+
@clients[name] = c
|
34
|
+
return c
|
35
|
+
end
|
36
|
+
|
37
|
+
c = try_client(name_moto, "#{Moto::DIR}/lib")
|
38
|
+
unless c.nil?
|
39
|
+
@clients[name] = c
|
40
|
+
return c
|
41
|
+
end
|
42
|
+
raise "Could not find client class for name #{name}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def try_client(name, dir)
|
46
|
+
begin
|
47
|
+
a = name.underscore.split('/')
|
48
|
+
client_path = a[1..20].join('/')
|
49
|
+
require "#{dir}/#{client_path}"
|
50
|
+
client_const = name.constantize
|
51
|
+
instance = client_const.new(self)
|
52
|
+
instance.init
|
53
|
+
instance.start_run
|
54
|
+
instance.start_test(@current_test)
|
55
|
+
return instance
|
56
|
+
rescue Exception => e
|
57
|
+
# puts e
|
58
|
+
# puts e.backtrace
|
59
|
+
return nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def const(key)
|
64
|
+
key = key.to_s
|
65
|
+
key = "#{@current_test.env.to_s}.#{key}" if @current_test.env != :__default
|
66
|
+
code = if key.include? '.'
|
67
|
+
"@config#{key.split('.').map{|a| "['#{a}']" }.join('')}"
|
68
|
+
else
|
69
|
+
"@config['#{key}']"
|
70
|
+
end
|
71
|
+
begin
|
72
|
+
v = eval code
|
73
|
+
raise if v.nil?
|
74
|
+
rescue
|
75
|
+
raise "There is no const defined for key: #{key}. Environment: #{ (@current_test.env == :__default) ? '<none>' : @current_test.env }"
|
76
|
+
end
|
77
|
+
v
|
78
|
+
end
|
79
|
+
|
80
|
+
def run
|
81
|
+
@tests.each do |test|
|
82
|
+
# remove log files from previous execution
|
83
|
+
Dir.glob("#{test.dir}/*.log").each {|f| File.delete f }
|
84
|
+
max_attempts = @runner.my_config[:max_attempts] || 1
|
85
|
+
@runner.environments.each do |env|
|
86
|
+
params_path = "#{test.dir}/#{test.filename}.yml"
|
87
|
+
params_all = [{}]
|
88
|
+
params_all = YAML.load(ERB.new(File.read(params_path)).result) if File.exists?(params_path)
|
89
|
+
#params_all = YAML.load_file(params_path) if File.exists?(params_path)
|
90
|
+
# or convert keys to symbols?
|
91
|
+
# params_all = YAML.load_file(params_path).map{|h| Hash[ h.map{|k,v| [ k.to_sym, v ] } ] } if File.exists?(params_path)
|
92
|
+
params_all.each_with_index do |params, params_index|
|
93
|
+
# TODO: add filtering out params that are specific to certain envs
|
94
|
+
(1..max_attempts).each do |attempt|
|
95
|
+
test.init(env, params, params_index)
|
96
|
+
# TODO: log path might be specified (to some extent) by the configuration
|
97
|
+
test.log_path = "#{test.dir}/#{test.name.gsub(/\s+/, '_').gsub('::', '_').gsub('/', '_')}.log"
|
98
|
+
@logger = Logger.new(File.open(test.log_path, File::WRONLY | File::TRUNC | File::CREAT))
|
99
|
+
# TODO: make logger level configurable
|
100
|
+
@logger.level = @runner.my_config[:log_level]
|
101
|
+
@current_test = test
|
102
|
+
@runner.listeners.each { |l| l.start_test(test) }
|
103
|
+
@clients.each_value { |c| c.start_test(test) }
|
104
|
+
test.before
|
105
|
+
@logger.info "Start: #{test.name} attempt #{attempt}/#{max_attempts}"
|
106
|
+
begin
|
107
|
+
test.run
|
108
|
+
rescue Exceptions::TestForcedPassed, Exceptions::TestForcedFailure, Exceptions::TestSkipped => e
|
109
|
+
logger.info(e.message)
|
110
|
+
@runner.result.add_error(test, e)
|
111
|
+
rescue Exception => e
|
112
|
+
@logger.error("#{e.class.name}: #{e.message}")
|
113
|
+
@logger.error(e.backtrace.join("\n"))
|
114
|
+
@runner.result.add_error(test, e)
|
115
|
+
end
|
116
|
+
test.after
|
117
|
+
@clients.each_value { |c| c.end_test(test) }
|
118
|
+
# HAX: running end_test on results now, on other listeners after logger is closed
|
119
|
+
@runner.listeners.first.end_test(test)
|
120
|
+
@logger.info("Result: #{test.result}")
|
121
|
+
@logger.close
|
122
|
+
@runner.listeners[1..-1].each { |l| l.end_test(test) }
|
123
|
+
break unless [Result::FAILURE, Result::ERROR].include? test.result
|
124
|
+
end # RETRY
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
@clients.each_value { |c| c.end_run }
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
129
132
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moto
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bartek Wilczek
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-12-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
127
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.0.
|
128
|
+
rubygems_version: 2.0.14.1
|
129
129
|
signing_key:
|
130
130
|
specification_version: 4
|
131
131
|
summary: Moto - yet another web testing framework
|