moto 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|