moto 0.0.0 → 0.0.3
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/bin/moto +3 -2
- data/lib/assert.rb +16 -0
- data/lib/cli.rb +52 -0
- data/lib/clients/base.rb +22 -0
- data/lib/clients/website.rb +54 -0
- data/lib/listeners/console.rb +9 -4
- data/lib/page.rb +32 -0
- data/lib/result.rb +8 -4
- data/lib/runner.rb +4 -10
- data/lib/runner_logging.rb +27 -0
- data/lib/test.rb +11 -4
- data/lib/test_generator.rb +62 -0
- data/lib/test_logging.rb +49 -0
- data/lib/thread_context.rb +62 -14
- metadata +15 -5
- data/lib/moto.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a53792d2e2c396c69d4304ea1ab6c1c4015fc895
|
4
|
+
data.tar.gz: f333327a20547acdd3f6ff7e4f97f15b0bea2016
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73bf56964886a0525c9c2140341ae722870ecf5963e9fe2d641e9a9ca8342d5b6ec1bc956a898051a96b5235a15657ed1457e8be1e7546f12cbb2bfdfbd3f55b
|
7
|
+
data.tar.gz: a5b6188e9320d21e1bce04b9c5759260cebc2dbae5f34f2f5a916be756f0019ca455278158e3cc363ec9d4adc6669a3b113104cc6d5b4c6dcf1d01ec8a63d028
|
data/bin/moto
CHANGED
data/lib/assert.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Moto
|
2
|
+
module Assert
|
3
|
+
|
4
|
+
def assert_equal(a, b)
|
5
|
+
assert(a==b, "Arguments should be equal: #{a} != #{b}")
|
6
|
+
end
|
7
|
+
|
8
|
+
def assert(condition, message)
|
9
|
+
unless condition
|
10
|
+
@context.runner.result.add_failure(self, message)
|
11
|
+
logger.error("ASSERTION FAILED: #{message}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
data/lib/cli.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'pp'
|
3
|
+
require 'yaml'
|
4
|
+
require 'active_support/inflector'
|
5
|
+
require 'active_support/core_ext/object/blank'
|
6
|
+
# require 'active_support/core_ext'
|
7
|
+
|
8
|
+
APP_DIR = Dir.pwd
|
9
|
+
MOTO_DIR = File.dirname(File.dirname(__FILE__))
|
10
|
+
|
11
|
+
# TODO detect if cwd contains MotoApp
|
12
|
+
|
13
|
+
require "#{APP_DIR}/config/moto"
|
14
|
+
|
15
|
+
require_relative './empty_listener'
|
16
|
+
require_relative './test_logging'
|
17
|
+
require_relative './runner_logging'
|
18
|
+
require_relative './runner'
|
19
|
+
require_relative './thread_context'
|
20
|
+
require_relative './result'
|
21
|
+
require_relative './assert'
|
22
|
+
require_relative './test'
|
23
|
+
require_relative './page'
|
24
|
+
require_relative './clients/base'
|
25
|
+
require_relative './listeners/base'
|
26
|
+
require_relative './listeners/console'
|
27
|
+
require_relative './test_generator'
|
28
|
+
|
29
|
+
module Moto
|
30
|
+
|
31
|
+
class Cli
|
32
|
+
|
33
|
+
def self.run(argv)
|
34
|
+
test_class_name = argv[0]
|
35
|
+
|
36
|
+
tg = TestGenerator.new(APP_DIR)
|
37
|
+
t = tg.generate(test_class_name)
|
38
|
+
|
39
|
+
tests = [t]
|
40
|
+
|
41
|
+
# parsing ARGV and creating config will come here
|
42
|
+
# instantiation of tests for ARGV params also happens here
|
43
|
+
# instantiate listeners/reporters
|
44
|
+
|
45
|
+
# listeners = []
|
46
|
+
listeners = [Moto::Listeners::Console]
|
47
|
+
runner = Moto::Runner.new(tests, listeners, thread_cnt: 3, environments: [:qa, :qa2])
|
48
|
+
runner.run
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/lib/clients/base.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Moto
|
2
|
+
module Clients
|
3
|
+
|
4
|
+
class Base
|
5
|
+
include Moto::EmptyListener
|
6
|
+
|
7
|
+
# include Moto::RunnerLogging
|
8
|
+
include Moto::TestLogging
|
9
|
+
|
10
|
+
attr_reader :context
|
11
|
+
|
12
|
+
def initialize(context)
|
13
|
+
@context = context
|
14
|
+
end
|
15
|
+
|
16
|
+
def init
|
17
|
+
# abstract
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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 init
|
15
|
+
# can be overriden
|
16
|
+
@options = {
|
17
|
+
capybara_backend: :selenium
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_run
|
22
|
+
# TODO: make session driver configurable
|
23
|
+
@session = Capybara::Session.new(@options[:capybara_backend])
|
24
|
+
@pages = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_run
|
28
|
+
@session.driver.browser.close # TODO: check that it really works
|
29
|
+
end
|
30
|
+
|
31
|
+
def start_test(test)
|
32
|
+
# @context.current_test.logger.info("Hi mom, I'm opening some pages!")
|
33
|
+
@session.reset_session!
|
34
|
+
end
|
35
|
+
|
36
|
+
def end_test(test)
|
37
|
+
@session.reset_session!
|
38
|
+
end
|
39
|
+
|
40
|
+
def page(p)
|
41
|
+
page_class_name = "#{self.class.name}Pages::#{p}"
|
42
|
+
page_class_name.gsub!('Moto::', 'MotoApp::')
|
43
|
+
if @pages[page_class_name].nil?
|
44
|
+
a = page_class_name.underscore.split('/')
|
45
|
+
page_path = a[1..20].join('/')
|
46
|
+
require "#{APP_DIR}/#{page_path}"
|
47
|
+
@pages[page_class_name] = page_class_name.constantize.new(self)
|
48
|
+
end
|
49
|
+
@pages[page_class_name]
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/listeners/console.rb
CHANGED
@@ -3,19 +3,24 @@ module Moto
|
|
3
3
|
class Console < Base
|
4
4
|
|
5
5
|
def start_run
|
6
|
-
|
6
|
+
puts "START"
|
7
7
|
end
|
8
8
|
|
9
9
|
def end_run
|
10
|
-
|
10
|
+
puts ""
|
11
|
+
puts "FINISHED: #{@runner.result.summary[:result]}, duration: #{Time.at(@runner.result.summary[:duration]).utc.strftime("%H:%M:%S")}"
|
12
|
+
puts "Tests executed: #{@runner.result.summary[:cnt_all]}"
|
13
|
+
puts " Passed: #{@runner.result.summary[:cnt_passed]}"
|
14
|
+
puts " Failure: #{@runner.result.summary[:cnt_failure]}"
|
15
|
+
puts " Error: #{@runner.result.summary[:cnt_error]}"
|
11
16
|
end
|
12
17
|
|
13
18
|
def start_test(test)
|
14
|
-
|
19
|
+
print test.name
|
15
20
|
end
|
16
21
|
|
17
22
|
def end_test(test)
|
18
|
-
|
23
|
+
puts "\t#{@runner.result[test.name][:result]}"
|
19
24
|
end
|
20
25
|
|
21
26
|
end
|
data/lib/page.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Moto
|
2
|
+
|
3
|
+
class Page
|
4
|
+
|
5
|
+
include Moto::TestLogging
|
6
|
+
|
7
|
+
ignore_logging :const
|
8
|
+
ignore_logging :session
|
9
|
+
|
10
|
+
def initialize(website)
|
11
|
+
@website = website
|
12
|
+
@context = @website.context
|
13
|
+
end
|
14
|
+
|
15
|
+
def const(key)
|
16
|
+
@website.context.const(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def session
|
20
|
+
@website.session
|
21
|
+
end
|
22
|
+
|
23
|
+
def page(p)
|
24
|
+
@context.client(@website.class.name.split('::').pop).page(p)
|
25
|
+
end
|
26
|
+
|
27
|
+
def raise_unless_loaded
|
28
|
+
raise "Invalid state: page #{self.class.name} is not loaded." unless loaded?
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
data/lib/result.rb
CHANGED
@@ -31,11 +31,14 @@ module Moto
|
|
31
31
|
@summary[:result] = PASSED
|
32
32
|
@summary[:result] = FAILURE unless @results.values.select{ |v| v[:failures].count > 0 }.empty?
|
33
33
|
@summary[:result] = ERROR unless @results.values.select{ |v| !v[:error].nil? }.empty?
|
34
|
-
|
34
|
+
@summary[:cnt_all] = @results.count
|
35
|
+
@summary[:cnt_passed] = @results.values.select{ |v| v[:result] == PASSED }.count
|
36
|
+
@summary[:cnt_failure] = @results.values.select{ |v| v[:result] == FAILURE }.count
|
37
|
+
@summary[:cnt_error] = @results.values.select{ |v| v[:result] == ERROR }.count
|
35
38
|
end
|
36
39
|
|
37
40
|
def start_test(test)
|
38
|
-
@results[test.name] = { class: test.class, result: RUNNING, env:
|
41
|
+
@results[test.name] = { class: test.class, result: RUNNING, env: test.env, params: test.params, name: test.name, error: nil, failures: [], started_at: Time.now.to_f }
|
39
42
|
end
|
40
43
|
|
41
44
|
def end_test(test)
|
@@ -43,8 +46,9 @@ module Moto
|
|
43
46
|
test.result = PASSED
|
44
47
|
test.result = FAILURE unless @results[test.name][:failures].empty?
|
45
48
|
test.result = ERROR unless @results[test.name][:error].nil?
|
49
|
+
@results[test.name][:finished_at] = Time.now.to_f
|
50
|
+
@results[test.name][:duration] = @results[test.name][:finished_at] - @results[test.name][:started_at]
|
46
51
|
@results[test.name][:result] = test.result
|
47
|
-
test.logger.info("Result: #{test.result}")
|
48
52
|
end
|
49
53
|
|
50
54
|
def add_failure(test, msg)
|
@@ -52,7 +56,7 @@ module Moto
|
|
52
56
|
end
|
53
57
|
|
54
58
|
def add_error(test, e)
|
55
|
-
|
59
|
+
@results[test.name][:error] = e
|
56
60
|
end
|
57
61
|
|
58
62
|
end
|
data/lib/runner.rb
CHANGED
@@ -5,6 +5,7 @@ module Moto
|
|
5
5
|
attr_reader :listeners
|
6
6
|
attr_reader :logger
|
7
7
|
attr_reader :environments
|
8
|
+
attr_reader :assert
|
8
9
|
|
9
10
|
def initialize(tests, listeners, config = {})
|
10
11
|
@tests = tests
|
@@ -12,10 +13,11 @@ module Moto
|
|
12
13
|
@threads = []
|
13
14
|
|
14
15
|
# TODO: initialize logger from config (yml or just ruby code)
|
15
|
-
@logger = Logger.new(STDOUT)
|
16
|
+
# @logger = Logger.new(STDOUT)
|
17
|
+
@logger = Logger.new(File.open("#{APP_DIR}/moto.log", File::WRONLY | File::APPEND | File::CREAT))
|
16
18
|
# @logger.level = Logger::WARN
|
17
19
|
|
18
|
-
@result =
|
20
|
+
@result = Result.new(self)
|
19
21
|
|
20
22
|
# TODO: validate envs, maybe no-env should be supported as well?
|
21
23
|
@environments = config[:environments]
|
@@ -38,14 +40,6 @@ module Moto
|
|
38
40
|
end
|
39
41
|
@threads.each{ |t| t.join }
|
40
42
|
@listeners.each { |l| l.end_run }
|
41
|
-
# aggregate result from @tests list
|
42
|
-
end
|
43
|
-
|
44
|
-
def assert(test, condition, message)
|
45
|
-
unless condition
|
46
|
-
@result.add_failure(test, message)
|
47
|
-
test.logger.error("ASSERTION FAILED: #{message}")
|
48
|
-
end
|
49
43
|
end
|
50
44
|
|
51
45
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Moto
|
2
|
+
module RunnerLogging
|
3
|
+
|
4
|
+
|
5
|
+
# TODO: merge it somehow with TestLogging. Parametrize logger object?
|
6
|
+
def self.included(cls)
|
7
|
+
def cls.method_added(name)
|
8
|
+
excluded_methods = Moto::EmptyListener.instance_methods(false)
|
9
|
+
excluded_methods << :new
|
10
|
+
excluded_methods << :initialize
|
11
|
+
# TODO: configure more excluded classes/methods
|
12
|
+
return if @added
|
13
|
+
@added = true # protect from recursion
|
14
|
+
original_method = "original_#{name}"
|
15
|
+
alias_method original_method, name
|
16
|
+
define_method(name) do |*args|
|
17
|
+
@context.runner.logger.debug("#{self.class.name}::#{__callee__} ENTER >>> #{args}") unless excluded_methods.include? name
|
18
|
+
result = send original_method, *args
|
19
|
+
@context.runner.logger.debug("#{self.class.name}::#{__callee__} LEAVE <<< #{result} ") unless excluded_methods.include? name
|
20
|
+
result
|
21
|
+
end
|
22
|
+
@added = false
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/test.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
module Moto
|
2
2
|
class Test
|
3
3
|
|
4
|
+
include Moto::Assert
|
5
|
+
|
4
6
|
attr_writer :context
|
5
7
|
attr_accessor :result
|
6
8
|
attr_reader :name
|
9
|
+
attr_reader :env
|
10
|
+
attr_reader :params
|
11
|
+
attr_writer :static_path
|
7
12
|
|
8
13
|
class << self
|
9
14
|
attr_accessor :_path
|
@@ -40,12 +45,18 @@ module Moto
|
|
40
45
|
|
41
46
|
def dir
|
42
47
|
# puts self.class.path
|
48
|
+
return File.dirname(@static_path) unless @static_path.nil?
|
43
49
|
File.dirname(self.path)
|
44
50
|
end
|
45
51
|
|
46
52
|
def filename
|
53
|
+
return File.basename(@static_path, ".*") unless @static_path.nil?
|
47
54
|
File.basename(path, ".*")
|
48
55
|
end
|
56
|
+
|
57
|
+
def const(key)
|
58
|
+
@context.const(key)
|
59
|
+
end
|
49
60
|
|
50
61
|
def run
|
51
62
|
# abstract
|
@@ -59,10 +70,6 @@ module Moto
|
|
59
70
|
# abstract
|
60
71
|
end
|
61
72
|
|
62
|
-
def assert(*args)
|
63
|
-
@context.runner.assert(self,*args)
|
64
|
-
end
|
65
|
-
|
66
73
|
def client(name)
|
67
74
|
@context.client(name)
|
68
75
|
end
|
@@ -0,0 +1,62 @@
|
|
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 "#{APP_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(class_name)
|
39
|
+
full_class_name = 'MotoApp::Tests::'+class_name
|
40
|
+
a = full_class_name.underscore.split('/')
|
41
|
+
test_path = (a[1..20]+[a[-1]]).join('/')
|
42
|
+
test_path = "#{APP_DIR}/#{test_path}.rb"
|
43
|
+
|
44
|
+
method_body = File.read(test_path) + "\n"
|
45
|
+
|
46
|
+
# MotoApp::Tests::Login::Short
|
47
|
+
consts = full_class_name.split('::')
|
48
|
+
class_name = consts.pop
|
49
|
+
|
50
|
+
consts.shift 2 # remove Moto::Test as already defined
|
51
|
+
m = create_module_tree(MotoApp::Tests, consts)
|
52
|
+
cls = Class.new(Moto::Test)
|
53
|
+
m.const_set(class_name.to_sym, cls)
|
54
|
+
|
55
|
+
test_object = cls.new
|
56
|
+
test_object.instance_eval( "def run\n #{method_body} \n end" )
|
57
|
+
test_object.static_path = test_path
|
58
|
+
test_object
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/test_logging.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Moto
|
2
|
+
module TestLogging
|
3
|
+
|
4
|
+
@@ignore_logging = []
|
5
|
+
|
6
|
+
def self.included(cls)
|
7
|
+
|
8
|
+
def cls.ignore_logging(method)
|
9
|
+
full_name = "#{self.name}::#{method}"
|
10
|
+
@@ignore_logging << full_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def cls.method_added(name)
|
14
|
+
|
15
|
+
Moto::EmptyListener.instance_methods(false).each do |m|
|
16
|
+
full_name = "#{self.name}::#{m}"
|
17
|
+
@@ignore_logging << full_name unless @@ignore_logging.include? full_name
|
18
|
+
end
|
19
|
+
@@ignore_logging << "#{self.name}::new"
|
20
|
+
@@ignore_logging << "#{self.name}::initialize"
|
21
|
+
|
22
|
+
return if @added
|
23
|
+
@added = true # protect from recursion
|
24
|
+
original_method = "original_#{name}"
|
25
|
+
alias_method original_method, name
|
26
|
+
define_method(name) do |*args|
|
27
|
+
full_name = "#{self.class.name}::#{__callee__}"
|
28
|
+
# TODO: use self.class.ancestors to figure out if ancestor::__callee__ is not in @@ignore_logging
|
29
|
+
skip_logging = @@ignore_logging.include? full_name
|
30
|
+
unless skip_logging
|
31
|
+
self.class.ancestors.each do |a|
|
32
|
+
ancestor_name = "#{a.name}::#{__callee__}"
|
33
|
+
if @@ignore_logging.include? ancestor_name
|
34
|
+
skip_logging = true
|
35
|
+
break
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@context.current_test.logger.debug("ENTER >>> #{self.class.name}::#{__callee__}(#{args})") unless skip_logging
|
40
|
+
result = send original_method, *args
|
41
|
+
@context.current_test.logger.debug("LEAVE <<< #{self.class.name}::#{__callee__} => #{result} ") unless skip_logging
|
42
|
+
result
|
43
|
+
end
|
44
|
+
@added = false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/thread_context.rb
CHANGED
@@ -4,51 +4,99 @@ module Moto
|
|
4
4
|
# all resources specific for single thread will be initialized here. E.g. browser session
|
5
5
|
attr_reader :runner
|
6
6
|
attr_reader :logger
|
7
|
+
attr_reader :log_path
|
8
|
+
attr_reader :current_test
|
7
9
|
|
8
10
|
def initialize(runner, tests)
|
9
11
|
@runner = runner
|
10
12
|
@tests = tests
|
13
|
+
@clients = {}
|
11
14
|
@tests.each do |t|
|
12
15
|
t.context = self
|
13
16
|
end
|
17
|
+
# TODO: add all *.yml files from that dir
|
18
|
+
@config = YAML.load_file("#{APP_DIR}/config/const.yml")
|
14
19
|
end
|
15
20
|
|
16
21
|
def client(name)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
return @clients[name] if @clients.key? name
|
23
|
+
|
24
|
+
name_app = 'MotoApp::Clients::' + name
|
25
|
+
name_moto = 'Moto::Clients::' + name
|
26
|
+
|
27
|
+
c = try_client(name_app, APP_DIR)
|
28
|
+
unless c.nil?
|
29
|
+
@clients[name] = c
|
30
|
+
return c
|
31
|
+
end
|
32
|
+
|
33
|
+
c = try_client(name_moto, "#{MOTO_DIR}/lib")
|
34
|
+
unless c.nil?
|
35
|
+
@clients[name] = c
|
36
|
+
return c
|
37
|
+
end
|
38
|
+
raise "Could not find client class for name #{name}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def try_client(name, dir)
|
42
|
+
begin
|
43
|
+
a = name.underscore.split('/')
|
44
|
+
client_path = a[1..20].join('/')
|
45
|
+
require "#{dir}/#{client_path}"
|
46
|
+
client_const = name.constantize
|
47
|
+
instance = client_const.new(self)
|
48
|
+
instance.init
|
49
|
+
instance.start_run
|
50
|
+
instance.start_test(@current_test)
|
51
|
+
return instance
|
52
|
+
rescue Exception => e
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def const(key)
|
58
|
+
# TODO: add support to consts with no env
|
59
|
+
@config[@current_test.env.to_s][key.to_s]
|
24
60
|
end
|
25
61
|
|
26
62
|
def run
|
27
63
|
@tests.each do |test|
|
28
|
-
# TODO: handle running same test in different environments / parameters - set name and logger
|
29
64
|
@runner.environments.each do |env|
|
30
65
|
params_path = "#{test.dir}/#{test.filename}.yml"
|
31
66
|
params_all = [{}]
|
32
67
|
params_all = YAML.load_file(params_path).map{|h| Hash[ h.map{|k,v| [ k.to_sym, v ] } ] } if File.exists?(params_path)
|
68
|
+
# params_all = YAML.load_file(params_path) if File.exists?(params_path)
|
33
69
|
params_all.each do |params|
|
70
|
+
# TODO: add filtering out params that are specific to certain envs
|
34
71
|
test.init(env, params)
|
35
72
|
# TODO: log path might be specified (to some extent) by the configuration
|
36
|
-
log_path = "#{test.dir}/#{test.name.gsub(/\s+/, '_').gsub('::', '_').gsub('/', '_')}.log"
|
37
|
-
|
73
|
+
@log_path = "#{test.dir}/#{test.name.gsub(/\s+/, '_').gsub('::', '_').gsub('/', '_')}.log"
|
74
|
+
# TODO: remove log files from previous execution
|
75
|
+
@logger = Logger.new(File.open(@log_path, File::WRONLY | File::TRUNC | File::CREAT))
|
38
76
|
# TODO: make logger level configurable
|
39
|
-
|
77
|
+
@logger.level = Moto::Config::LOG_LEVEL
|
40
78
|
@current_test = test
|
41
79
|
@runner.listeners.each { |l| l.start_test(test) }
|
80
|
+
@clients.each_value { |c| c.start_test(test) }
|
42
81
|
test.before
|
43
|
-
|
44
|
-
|
82
|
+
@logger.info "Start: #{test.name}"
|
83
|
+
begin
|
84
|
+
test.run
|
85
|
+
rescue Exception => e
|
86
|
+
@logger.error("#{e.class.name}: #{e.message}")
|
87
|
+
@logger.error(e.backtrace.join("\n"))
|
88
|
+
@runner.result.add_error(test, e)
|
89
|
+
end
|
45
90
|
test.after
|
91
|
+
@clients.each_value { |c| c.end_test(test) }
|
46
92
|
@runner.listeners.each { |l| l.end_test(test) }
|
93
|
+
@logger.info("Result: #{test.result}")
|
47
94
|
@logger.close
|
48
95
|
end
|
49
96
|
end
|
50
97
|
end
|
98
|
+
@clients.each_value { |c| c.end_run }
|
51
99
|
end
|
52
|
-
|
100
|
+
|
53
101
|
end
|
54
102
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bartek Wilczek
|
@@ -11,23 +11,33 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2015-08-07 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
14
|
+
description: This is a development version of a rails philosophy inspired framework
|
15
|
+
for web applications functional testing. It supports (or will support) threading,
|
16
|
+
scenario parametrization, different test environments and much more. Stay tuned
|
17
|
+
for v.1.0.0 in the near future.
|
15
18
|
email: bw@vouk.info
|
16
19
|
executables:
|
17
20
|
- moto
|
18
21
|
extensions: []
|
19
22
|
extra_rdoc_files: []
|
20
23
|
files:
|
24
|
+
- lib/assert.rb
|
25
|
+
- lib/cli.rb
|
21
26
|
- lib/empty_listener.rb
|
22
|
-
- lib/
|
27
|
+
- lib/page.rb
|
23
28
|
- lib/result.rb
|
24
29
|
- lib/runner.rb
|
30
|
+
- lib/runner_logging.rb
|
25
31
|
- lib/test.rb
|
32
|
+
- lib/test_generator.rb
|
33
|
+
- lib/test_logging.rb
|
26
34
|
- lib/thread_context.rb
|
35
|
+
- lib/clients/base.rb
|
36
|
+
- lib/clients/website.rb
|
27
37
|
- lib/listeners/base.rb
|
28
38
|
- lib/listeners/console.rb
|
29
39
|
- bin/moto
|
30
|
-
homepage:
|
40
|
+
homepage: https://github.com/bwilczek/moto
|
31
41
|
licenses:
|
32
42
|
- MIT
|
33
43
|
metadata: {}
|
@@ -50,5 +60,5 @@ rubyforge_project:
|
|
50
60
|
rubygems_version: 2.0.14
|
51
61
|
signing_key:
|
52
62
|
specification_version: 4
|
53
|
-
summary: Moto - yet another testing framework
|
63
|
+
summary: Moto - yet another web testing framework
|
54
64
|
test_files: []
|
data/lib/moto.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
require 'yaml'
|
3
|
-
require 'active_support/inflector'
|
4
|
-
require 'active_support/core_ext/object/blank'
|
5
|
-
|
6
|
-
require_relative '../lib/empty_listener'
|
7
|
-
require_relative '../lib/runner'
|
8
|
-
require_relative '../lib/thread_context'
|
9
|
-
require_relative '../lib/result'
|
10
|
-
require_relative '../lib/test'
|
11
|
-
require_relative '../lib/listeners/base'
|
12
|
-
require_relative '../lib/listeners/console'
|
13
|
-
|
14
|
-
APP_DIR = Dir.pwd
|
15
|
-
|
16
|
-
class MotoCliRunner
|
17
|
-
|
18
|
-
def self.run(argv)
|
19
|
-
t = argv[0]
|
20
|
-
t = 'MotoApp::Tests::'+t
|
21
|
-
a = t.underscore.split('/')
|
22
|
-
test_path = (a[1..20]+[a[-1]]).join('/')
|
23
|
-
|
24
|
-
# TODO: check if this path and constat exists
|
25
|
-
require "#{APP_DIR}/#{test_path}"
|
26
|
-
test_const = t.safe_constantize
|
27
|
-
|
28
|
-
tests = [
|
29
|
-
test_const.new
|
30
|
-
]
|
31
|
-
|
32
|
-
# parsing ARGV and creating config will come here
|
33
|
-
# instantiation of tests for ARGV params also happens here
|
34
|
-
# instantiate listeners/reporters
|
35
|
-
|
36
|
-
# listeners = []
|
37
|
-
listeners = [Moto::Listeners::Console]
|
38
|
-
runner = Moto::Runner.new(tests, listeners, thread_cnt: 3, environments: [:qa2, :qa])
|
39
|
-
runner.run
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|