moto 0.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/bin/moto +4 -0
- data/lib/empty_listener.rb +17 -0
- data/lib/listeners/base.rb +26 -0
- data/lib/listeners/console.rb +23 -0
- data/lib/moto.rb +42 -0
- data/lib/result.rb +59 -0
- data/lib/runner.rb +52 -0
- data/lib/test.rb +71 -0
- data/lib/thread_context.rb +54 -0
- metadata +54 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e048efe2a7dae21ba01da0503fdeb40e56755827
|
4
|
+
data.tar.gz: 00882f74920d1fab0729c015e8260ecba2b115ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8b89e9d40644d2a751c9e4fd7455d40395f3c2a7d682cec532e6ac8dd9cf02497338e26952ae8156eee510d9289a21dc61f286fcb8c071e29400d9f2fb88931f
|
7
|
+
data.tar.gz: e8710637b4dbbb2ccd4e2d9412f932033e79fc7baee4713b82926a4e6ac5c83732b1b76f9a02521bb714cc1835ea436171f3d7677a4e339bddcdb18b6ddca3ed
|
data/bin/moto
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Moto
|
2
|
+
module Listeners
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize(runner)
|
6
|
+
@runner=runner
|
7
|
+
end
|
8
|
+
|
9
|
+
def start_run
|
10
|
+
# abstract
|
11
|
+
end
|
12
|
+
|
13
|
+
def end_run
|
14
|
+
# abstract
|
15
|
+
end
|
16
|
+
|
17
|
+
def start_test(test)
|
18
|
+
# abstract
|
19
|
+
end
|
20
|
+
|
21
|
+
def end_test(test)
|
22
|
+
# abstract
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Moto
|
2
|
+
module Listeners
|
3
|
+
class Console < Base
|
4
|
+
|
5
|
+
def start_run
|
6
|
+
@runner.logger.info("Starting...")
|
7
|
+
end
|
8
|
+
|
9
|
+
def end_run
|
10
|
+
@runner.logger.info("...done: #{@runner.result.summary[:result]}, duration: #{@runner.result.summary[:duration]}")
|
11
|
+
end
|
12
|
+
|
13
|
+
def start_test(test)
|
14
|
+
@runner.logger.info("Starting test #{test.name}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def end_test(test)
|
18
|
+
@runner.logger.info("Ending test #{test.name} with result #{@runner.result[test.name][:result]}")
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/moto.rb
ADDED
@@ -0,0 +1,42 @@
|
|
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
|
data/lib/result.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module Moto
|
2
|
+
class Result
|
3
|
+
|
4
|
+
PENDING = :pending # -2
|
5
|
+
RUNNING = :running # -1
|
6
|
+
PASSED = :passed # 0
|
7
|
+
FAILURE = :failure # 1
|
8
|
+
ERROR = :error # 2
|
9
|
+
|
10
|
+
attr_reader :summary
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
@results[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(runner)
|
17
|
+
@runner = runner
|
18
|
+
@results = {}
|
19
|
+
@summary = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def start_run
|
23
|
+
# start timer
|
24
|
+
@summary[:started_at] = Time.now.to_f
|
25
|
+
end
|
26
|
+
|
27
|
+
def end_run
|
28
|
+
# info about duration and overall execution result
|
29
|
+
@summary[:finished_at] = Time.now.to_f
|
30
|
+
@summary[:duration] = @summary[:finished_at] - @summary[:started_at]
|
31
|
+
@summary[:result] = PASSED
|
32
|
+
@summary[:result] = FAILURE unless @results.values.select{ |v| v[:failures].count > 0 }.empty?
|
33
|
+
@summary[:result] = ERROR unless @results.values.select{ |v| !v[:error].nil? }.empty?
|
34
|
+
# TODO: calculate count and percentage of errors/failures
|
35
|
+
end
|
36
|
+
|
37
|
+
def start_test(test)
|
38
|
+
@results[test.name] = { class: test.class, result: RUNNING, env: nil, params: nil, name: test.name, error: nil, failures: [] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def end_test(test)
|
42
|
+
# calculate result basing on errors/failures
|
43
|
+
test.result = PASSED
|
44
|
+
test.result = FAILURE unless @results[test.name][:failures].empty?
|
45
|
+
test.result = ERROR unless @results[test.name][:error].nil?
|
46
|
+
@results[test.name][:result] = test.result
|
47
|
+
test.logger.info("Result: #{test.result}")
|
48
|
+
end
|
49
|
+
|
50
|
+
def add_failure(test, msg)
|
51
|
+
@results[test.name][:failures] << msg
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_error(test, e)
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
data/lib/runner.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Moto
|
2
|
+
class Runner
|
3
|
+
|
4
|
+
attr_reader :result
|
5
|
+
attr_reader :listeners
|
6
|
+
attr_reader :logger
|
7
|
+
attr_reader :environments
|
8
|
+
|
9
|
+
def initialize(tests, listeners, config = {})
|
10
|
+
@tests = tests
|
11
|
+
@config = config
|
12
|
+
@threads = []
|
13
|
+
|
14
|
+
# TODO: initialize logger from config (yml or just ruby code)
|
15
|
+
@logger = Logger.new(STDOUT)
|
16
|
+
# @logger.level = Logger::WARN
|
17
|
+
|
18
|
+
@result = Moto::Result.new(self)
|
19
|
+
|
20
|
+
# TODO: validate envs, maybe no-env should be supported as well?
|
21
|
+
@environments = config[:environments]
|
22
|
+
|
23
|
+
@listeners = []
|
24
|
+
listeners.each do |l|
|
25
|
+
@listeners << l.new(self)
|
26
|
+
end
|
27
|
+
@listeners.unshift(@result)
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
@listeners.each { |l| l.start_run }
|
32
|
+
test_slices = @tests.each_slice((@tests.size.to_f/@config[:thread_cnt]).ceil).to_a
|
33
|
+
(0...test_slices.count).each do |i|
|
34
|
+
@threads << Thread.new do
|
35
|
+
tc = ThreadContext.new(self, test_slices[i])
|
36
|
+
tc.run
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@threads.each{ |t| t.join }
|
40
|
+
@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
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/lib/test.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
module Moto
|
2
|
+
class Test
|
3
|
+
|
4
|
+
attr_writer :context
|
5
|
+
attr_accessor :result
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :_path
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.inherited(k)
|
13
|
+
k._path = caller.first.match( /(.+):\d+:in/ )[1]
|
14
|
+
end
|
15
|
+
|
16
|
+
def path
|
17
|
+
self.class._path
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
# @context = context
|
22
|
+
@result = Moto::Result::PENDING
|
23
|
+
end
|
24
|
+
|
25
|
+
def init(env, params)
|
26
|
+
@env = env
|
27
|
+
@params = params
|
28
|
+
set_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def logger
|
32
|
+
@context.logger
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_name
|
36
|
+
return @name = "#{self.class.to_s}/#{@env}" if @params.empty?
|
37
|
+
return @name = "#{self.class.to_s}/#{@env}/#{@params[:__name]}" if @params.key?(:__name)
|
38
|
+
@name = self.class.to_s
|
39
|
+
end
|
40
|
+
|
41
|
+
def dir
|
42
|
+
# puts self.class.path
|
43
|
+
File.dirname(self.path)
|
44
|
+
end
|
45
|
+
|
46
|
+
def filename
|
47
|
+
File.basename(path, ".*")
|
48
|
+
end
|
49
|
+
|
50
|
+
def run
|
51
|
+
# abstract
|
52
|
+
end
|
53
|
+
|
54
|
+
def before
|
55
|
+
# abstract
|
56
|
+
end
|
57
|
+
|
58
|
+
def after
|
59
|
+
# abstract
|
60
|
+
end
|
61
|
+
|
62
|
+
def assert(*args)
|
63
|
+
@context.runner.assert(self,*args)
|
64
|
+
end
|
65
|
+
|
66
|
+
def client(name)
|
67
|
+
@context.client(name)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Moto
|
2
|
+
class ThreadContext
|
3
|
+
|
4
|
+
# all resources specific for single thread will be initialized here. E.g. browser session
|
5
|
+
attr_reader :runner
|
6
|
+
attr_reader :logger
|
7
|
+
|
8
|
+
def initialize(runner, tests)
|
9
|
+
@runner = runner
|
10
|
+
@tests = tests
|
11
|
+
@tests.each do |t|
|
12
|
+
t.context = self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def client(name)
|
17
|
+
# TODO: implement registry caching per name+env
|
18
|
+
name = 'MotoApp::Clients::' + name
|
19
|
+
a = name.underscore.split('/')
|
20
|
+
test_path = (a[1..20]+[a[-1]]).join('/')
|
21
|
+
require "#{APP_DIR}/#{test_path}"
|
22
|
+
client_const = name.safe_constantize
|
23
|
+
client_const.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
@tests.each do |test|
|
28
|
+
# TODO: handle running same test in different environments / parameters - set name and logger
|
29
|
+
@runner.environments.each do |env|
|
30
|
+
params_path = "#{test.dir}/#{test.filename}.yml"
|
31
|
+
params_all = [{}]
|
32
|
+
params_all = YAML.load_file(params_path).map{|h| Hash[ h.map{|k,v| [ k.to_sym, v ] } ] } if File.exists?(params_path)
|
33
|
+
params_all.each do |params|
|
34
|
+
test.init(env, params)
|
35
|
+
# 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
|
+
@logger = Logger.new(File.open(log_path, File::WRONLY | File::TRUNC | File::CREAT))
|
38
|
+
# TODO: make logger level configurable
|
39
|
+
# @logger.level = Logger::INFO
|
40
|
+
@current_test = test
|
41
|
+
@runner.listeners.each { |l| l.start_test(test) }
|
42
|
+
test.before
|
43
|
+
# TODO: handle exception thrown during test run
|
44
|
+
test.run
|
45
|
+
test.after
|
46
|
+
@runner.listeners.each { |l| l.end_test(test) }
|
47
|
+
@logger.close
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: moto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bartek Wilczek
|
8
|
+
- Maciej Przybylski
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-08-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: With a fancy description
|
15
|
+
email: bw@vouk.info
|
16
|
+
executables:
|
17
|
+
- moto
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/empty_listener.rb
|
22
|
+
- lib/moto.rb
|
23
|
+
- lib/result.rb
|
24
|
+
- lib/runner.rb
|
25
|
+
- lib/test.rb
|
26
|
+
- lib/thread_context.rb
|
27
|
+
- lib/listeners/base.rb
|
28
|
+
- lib/listeners/console.rb
|
29
|
+
- bin/moto
|
30
|
+
homepage: http://vouk.info
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubyforge_project:
|
50
|
+
rubygems_version: 2.0.14
|
51
|
+
signing_key:
|
52
|
+
specification_version: 4
|
53
|
+
summary: Moto - yet another testing framework
|
54
|
+
test_files: []
|