moto 0.0.61 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 79fd340e02c8fc99118145bfff406152d69616b4
4
- data.tar.gz: 0409af8e817650b861ff323af7fd2d4689adffa5
3
+ metadata.gz: 5c6fc26ad79a37b98a47def96713f98aeb645d7a
4
+ data.tar.gz: 319b20fd048182b400a165c5f947eca5da265850
5
5
  SHA512:
6
- metadata.gz: aff3af12f4ce522fd01d733556a3a9b04c6ef155edbbbcadd7556ae00a8d0c4d38da9946907df1094f2b6e806fd79695a13877c2626ff08876faceb7ee5b82bc
7
- data.tar.gz: fa8bdff3222419dda771bee36e38615c50008d87ba500a8905ae010ac133b5f1591846b21ff9d6c2d037c15a838c0b3215b2b4cf2e1d087a87905048763c1a6d
6
+ metadata.gz: b7094905897ffa05fd13dcc0e170d3f9a9faf54b76a27aaff5776f353d664c035f786bab3fe9b8585ce594584a3c03c88f1d852e35e991787eb5eece832134dc
7
+ data.tar.gz: 8fb71b7424b346314b29cd76f232207db2fc3f19214adfbbbd3e2f9239896e8610b568ca3e192759e2ed87bb649b2971059a7f9098db31cb2f82cc9cdb885b92
data/lib/cli.rb CHANGED
@@ -13,7 +13,6 @@ module Moto
13
13
  end
14
14
 
15
15
  require_relative './empty_listener'
16
- require_relative './forward_context_methods'
17
16
  require_relative './test_logging'
18
17
  require_relative './runner_logging'
19
18
  require_relative './runner/test_runner'
@@ -3,23 +3,12 @@ module Moto
3
3
 
4
4
  class Base
5
5
  include Moto::EmptyListener
6
- include Moto::ForwardContextMethods
7
6
 
8
7
  # include Moto::RunnerLogging
9
8
  include Moto::TestLogging
10
9
 
11
- attr_reader :context
12
-
13
10
  ignore_logging(:handle_test_exception)
14
11
 
15
- def initialize(context)
16
- @context = context
17
- end
18
-
19
- def init
20
- # abstract
21
- end
22
-
23
12
  def handle_test_exception(test, exception)
24
13
  # abstract
25
14
  end
@@ -31,6 +20,11 @@ module Moto
31
20
  Moto::Lib::Config.environment_const(key)
32
21
  end
33
22
 
23
+ # Access client defined in Moto or MotoApp via it's name
24
+ def client(name)
25
+ Thread.current['clients_manager'].client(name)
26
+ end
27
+
34
28
  end
35
29
  end
36
30
  end
@@ -0,0 +1,51 @@
1
+ module Moto
2
+ module Lib
3
+ module Clients
4
+ class ClientsManager
5
+
6
+ attr_reader :clients
7
+
8
+ def initialize
9
+ @clients = {}
10
+ end
11
+
12
+ def client(name)
13
+ return @clients[name] if @clients.key? name
14
+
15
+ name_app = 'MotoApp::Lib::Clients::' + name
16
+ name_moto = 'Moto::Clients::' + name
17
+
18
+ client = try_client(name_app, "#{MotoApp::DIR}/")
19
+ if client
20
+ @clients[name] = client
21
+ return client
22
+ end
23
+
24
+ client = try_client(name_moto, "#{Moto::DIR}/lib/")
25
+ if client
26
+ @clients[name] = client
27
+ return client
28
+ end
29
+
30
+ raise "Could not find client class for name: #{name}"
31
+ end
32
+
33
+ def try_client(name, dir)
34
+ client_path = name.underscore.split('/')[1..-1].join('/')
35
+
36
+ if File.file?(dir + client_path + '.rb')
37
+ require dir + client_path
38
+ client_const = name.constantize
39
+ instance = client_const.new
40
+ instance.start_run
41
+ instance
42
+ else
43
+ nil
44
+ end
45
+ end
46
+ private :try_client
47
+
48
+ end
49
+ end
50
+ end
51
+ end
@@ -6,15 +6,25 @@ module Moto
6
6
 
7
7
  class Website < Moto::Clients::Base
8
8
 
9
- attr_reader :session
10
-
11
- ignore_logging(:page)
12
- ignore_logging(:context)
13
9
  ignore_logging(:session)
14
10
 
15
- def init
11
+ def initialize
16
12
  register_grid_driver
17
13
  register_chrome_driver
14
+
15
+ if config[:default_selector]
16
+ Capybara.default_selector = config[:default_selector]
17
+ end
18
+ end
19
+
20
+ # Returns Capybara session, if none was available for this thread it will create one.
21
+ def session
22
+ if Thread.current['capybara_session'].nil?
23
+ Thread.current['capybara_session'] = Capybara::Session.new(config[:default_driver])
24
+ Thread.current['capybara_session'].driver.browser.manage.window.maximize
25
+ end
26
+
27
+ Thread.current['capybara_session']
18
28
  end
19
29
 
20
30
  # @return [Hash] Config section for Capybara driver.
@@ -24,13 +34,7 @@ module Moto
24
34
  private :config
25
35
 
26
36
  def start_run
27
- # TODO: make session driver configurable
28
- if config[:default_selector]
29
- Capybara.default_selector = config[:default_selector]
30
- end
31
37
 
32
- Thread.current['capybara_session'] = Capybara::Session.new(config[:default_driver])
33
- @pages = {}
34
38
  end
35
39
 
36
40
  def end_run
@@ -44,18 +48,6 @@ module Moto
44
48
  def end_test(test)
45
49
  Thread.current['capybara_session'].reset_session!
46
50
  end
47
- #TODO fix moto to use Lib module
48
- def page(p)
49
- page_class_name = "#{self.class.name}::Pages::#{p}"
50
- page_class_name.gsub!('Moto::', 'MotoApp::Lib::')
51
- if @pages[page_class_name].nil?
52
- a = page_class_name.underscore.split('/')
53
- page_path = a[1..-1].join('/')
54
- require "#{MotoApp::DIR}/#{page_path}"
55
- @pages[page_class_name] = page_class_name.constantize.new(self)
56
- end
57
- @pages[page_class_name]
58
- end
59
51
 
60
52
  def register_grid_driver
61
53
  grid_config = config[:grid]
@@ -1,23 +1,14 @@
1
1
  module Moto
2
-
3
2
  class Page
4
3
 
5
4
  include Moto::TestLogging
6
- include Moto::ForwardContextMethods
7
5
 
8
6
  ignore_logging :const
9
7
  ignore_logging :session
10
8
 
11
- attr_reader :website
12
- attr_reader :context
13
-
14
- def initialize(website)
15
- @website = website
16
- @context = @website.context
17
- end
18
-
19
- def page(p)
20
- @context.client(@website.class.name.split('::').pop).page(p)
9
+ # Returns Capybara's session by means of on-the-fly client&session creation.
10
+ def session
11
+ Thread.current['clients_manager'].client('Website').session
21
12
  end
22
13
 
23
14
  def raise_unless_loaded
@@ -91,25 +91,18 @@ module Moto
91
91
  # Generates test instances, based on fully defined class file
92
92
  # @return [Moto::Test::Base]
93
93
  def generate_for_full_class_code(test_path_absolute)
94
-
95
- begin
96
- require test_path_absolute
97
- rescue Exception
98
- # will catch an error with non existent base class in test and stop it from breaking whole batch of tests
99
- # no need to handle it here, next begin/rescue clause in this function will finish the job
100
- end
101
-
102
94
  # Checking if it's possible to create test based on provided path. In case something is wrong with
103
95
  # modules structure in class itself Moto::Test::Base will be instantized with raise injected into its run()
104
96
  # so we can have proper reporting and summary even if the test doesn't execute.
105
97
  begin
98
+ require test_path_absolute
106
99
  class_name = test_path_absolute.gsub("#{MotoApp::DIR}/", 'moto_app/').camelize.chomp('.rb').constantize
107
100
  test_object = class_name.new
108
- rescue NameError
101
+ rescue NameError => e
109
102
  class_name = Moto::Test::Base
110
103
  test_object = class_name.new
111
104
 
112
- error_message = "ERROR: Invalid module structure: #{test_path_absolute.gsub("#{MotoApp::DIR}/", 'moto_app/').camelize.chomp('.rb')}"
105
+ error_message = "ERROR: Invalid test: #{test_path_absolute.gsub("#{MotoApp::DIR}/", 'moto_app/').camelize.chomp('.rb')}.\nMESSAGE: #{e}"
113
106
  inject_error_to_test(test_object, error_message)
114
107
  end
115
108
 
@@ -5,15 +5,11 @@ module Moto
5
5
  module Runner
6
6
  class TestRunner
7
7
 
8
- attr_reader :logger
9
8
  attr_reader :test_reporter
10
9
 
11
10
  def initialize(test_paths_absolute, test_reporter)
12
11
  @test_paths_absolute = test_paths_absolute
13
12
  @test_reporter = test_reporter
14
-
15
- # TODO: initialize logger from config (yml or just ruby code)
16
- @logger = Logger.new(File.open("#{MotoApp::DIR}/moto.log", File::WRONLY | File::APPEND | File::CREAT))
17
13
  end
18
14
 
19
15
  def run
@@ -30,10 +26,15 @@ module Moto
30
26
  # Create as many threads as we're allowed by the config file.
31
27
  # test_provider.get_test - will invoke Queue.pop thus putting the thread to sleep
32
28
  # once there is no more work.
29
+
30
+ Thread.abort_on_exception = true
31
+
33
32
  (1..threads_max).each do |index|
34
33
  Thread.new do
35
34
  Thread.current[:id] = index
36
35
  loop do
36
+ Thread.current['clients_manager'] = Moto::Lib::Clients::ClientsManager.new
37
+
37
38
  tc = ThreadContext.new(test_provider.get_test, @test_reporter)
38
39
  tc.run
39
40
  end
@@ -1,103 +1,58 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
3
  require_relative '../../lib/config'
4
+ require_relative '../../lib/clients/clients_manager'
4
5
 
5
6
  module Moto
6
7
  module Runner
7
8
  class ThreadContext
8
9
 
9
- # all resources specific for single thread will be initialized here. E.g. browser session
10
- attr_reader :logger
11
10
  attr_reader :test
12
11
 
13
12
  def initialize(test, test_reporter)
14
13
  @test = test
15
- @clients = {}
16
- @test.context = self
17
14
  @test_reporter = test_reporter
18
15
 
19
- # TODO: temporary fix
20
- Thread.current['context'] = self
21
- end
22
-
23
- def client(name)
24
- return @clients[name] if @clients.key? name
25
-
26
- name_app = 'MotoApp::Lib::Clients::' + name
27
- name_moto = 'Moto::Clients::' + name
28
-
29
- c = try_client(name_app, "#{MotoApp::DIR}/")
30
- unless c.nil?
31
- @clients[name] = c
32
- return c
16
+ log_directory = File.dirname(@test.log_path)
17
+ if !File.directory?(log_directory)
18
+ FileUtils.mkdir_p(log_directory)
33
19
  end
34
20
 
35
- c = try_client(name_moto, "#{Moto::DIR}/lib")
36
- unless c.nil?
37
- @clients[name] = c
38
- return c
39
- end
40
- raise "Could not find client class for name #{name}"
21
+ Thread.current['logger'] = Logger.new(File.open(@test.log_path, File::WRONLY | File::TRUNC | File::CREAT))
22
+ Thread.current['logger'].level = config[:test_log_level] || Logger::DEBUG
41
23
  end
42
24
 
43
- def try_client(name, dir)
44
- begin
45
- a = name.underscore.split('/')
46
- client_path = a[1..-1].join('/')
47
- require "#{dir}/#{client_path}"
48
- client_const = name.constantize
49
- instance = client_const.new(self)
50
- instance.init
51
- instance.start_run
52
- instance.start_test(@test)
53
- return instance
54
- rescue Exception => e
55
- # puts e
56
- # puts e.backtrace
57
- return nil
58
- end
59
- end
60
-
61
- #
62
25
  def run
63
26
  max_attempts = config[:test_attempt_max] || 1
64
27
  sleep_time = config[:test_attempt_sleep] || 0
65
28
 
66
- log_directory = File.dirname(@test.log_path)
67
- if !File.directory?(log_directory)
68
- FileUtils.mkdir_p(log_directory)
69
- end
70
-
71
- @logger = Logger.new(File.open(@test.log_path, File::WRONLY | File::TRUNC | File::CREAT))
72
- @logger.level = config[:test_log_level] || Logger::DEBUG
73
-
74
29
  # Reporting: start_test
75
30
  @test_reporter.report_start_test(@test.status)
76
31
 
77
32
  (1..max_attempts).each do |attempt|
78
33
 
79
- @clients.each_value { |c| c.start_test(@test) }
34
+ Thread.current['clients_manager'].clients.each_value { |c| c.start_test(@test) }
80
35
  @test.before
81
- @logger.info "Start: #{@test.name} attempt #{attempt}/#{max_attempts}"
36
+ Thread.current['logger'].info("Start: #{@test.name} attempt #{attempt}/#{max_attempts}")
82
37
 
83
38
  begin
84
39
  @test.run_test
85
40
  rescue Exceptions::TestForcedPassed, Exceptions::TestForcedFailure, Exceptions::TestSkipped => e
86
- @logger.info(e.message)
41
+ Thread.current['logger'].info(e.message)
87
42
  rescue Exception => e
88
- @logger.error("#{e.class.name}: #{e.message}")
89
- @logger.error(e.backtrace.join("\n"))
90
- @clients.each_value { |c| c.handle_test_exception(@test, e) }
43
+ Thread.current['logger'].error("#{e.class.name}: #{e.message}")
44
+ Thread.current['logger'].error(e.backtrace.join("\n"))
45
+ Thread.current['clients_manager'].clients.each_value { |c| c.handle_test_exception(@test, e) }
91
46
  end
92
47
 
93
48
  @test.after
94
- @clients.each_value { |c| c.end_test(@test) }
49
+ Thread.current['clients_manager'].clients.each_value { |c| c.end_test(@test) }
95
50
 
96
- @logger.info("Result: #{@test.status.results.last.code}")
51
+ Thread.current['logger'].info("Result: #{@test.status.results.last.code}")
97
52
 
98
- # test should have another attempt only in case of an error
99
- # pass, skip and fail statuses end attempts
100
- if @test.status.results.last.code != Moto::Test::Result::ERROR
53
+ # test should have another attempt in case of an error / failure / none at all
54
+ if (@test.status.results.last.code == Moto::Test::Result::ERROR && !Moto::Lib::Config.moto[:test_reattempt_on_error]) ||
55
+ (@test.status.results.last.code == Moto::Test::Result::FAILURE && !Moto::Lib::Config.moto[:test_reattempt_on_fail] )
101
56
  break
102
57
  end
103
58
 
@@ -109,12 +64,12 @@ module Moto
109
64
  end # Make another attempt
110
65
 
111
66
  # Close and flush stream to file
112
- @logger.close
67
+ Thread.current['logger'].close
113
68
 
114
69
  # Reporting: end_test
115
70
  @test_reporter.report_end_test(@test.status)
116
71
 
117
- @clients.each_value { |c| c.end_run }
72
+ Thread.current['clients_manager'].clients.each_value { |c| c.end_run }
118
73
 
119
74
  end
120
75
 
@@ -1,7 +1,6 @@
1
1
  module Moto
2
2
  module RunnerLogging
3
3
 
4
-
5
4
  # TODO: merge it somehow with TestLogging. Parametrize logger object?
6
5
  def self.included(cls)
7
6
  def cls.method_added(name)
@@ -14,9 +13,9 @@ module Moto
14
13
  original_method = "original_#{name}"
15
14
  alias_method original_method, name
16
15
  define_method(name) do |*args|
17
- @context.runner.logger.debug("#{self.class.name}::#{__callee__} ENTER >>> #{args}") unless excluded_methods.include? name
16
+ Thread.current['logger'].debug("#{self.class.name}::#{__callee__} ENTER >>> #{args}") unless excluded_methods.include? name
18
17
  result = send original_method, *args
19
- @context.runner.logger.debug("#{self.class.name}::#{__callee__} LEAVE <<< #{result} ") unless excluded_methods.include? name
18
+ Thread.current['logger'].debug("#{self.class.name}::#{__callee__} LEAVE <<< #{result} ") unless excluded_methods.include? name
20
19
  result
21
20
  end
22
21
  @added = false
@@ -4,10 +4,7 @@ module Moto
4
4
  module Test
5
5
  class Base
6
6
 
7
- include Moto::ForwardContextMethods
8
-
9
7
  attr_reader :name
10
- attr_writer :context
11
8
  attr_reader :env
12
9
  attr_reader :params
13
10
  attr_accessor :static_path
@@ -156,7 +153,7 @@ module Moto
156
153
  end
157
154
 
158
155
  status.log_failure("ASSERTION FAILED in line #{line_number}: #{message}")
159
- logger.error(message)
156
+ Thread.current['logger'].error(message)
160
157
  end
161
158
  end
162
159
 
@@ -167,6 +164,14 @@ module Moto
167
164
  Moto::Lib::Config.environment_const(key)
168
165
  end
169
166
 
167
+ def client(name)
168
+ Thread.current['clients_manager'].client(name)
169
+ end
170
+
171
+ def session
172
+ client('Website').session
173
+ end
174
+
170
175
  end
171
176
  end
172
177
  end
@@ -36,10 +36,10 @@ module Moto
36
36
  end
37
37
  end
38
38
  end
39
- @context.test.logger.debug("ENTER >>> #{self.class.name}::#{__callee__}(#{args})") unless skip_logging
39
+ Thread.current['logger'].debug("ENTER >>> #{self.class.name}::#{__callee__}(#{args})") unless skip_logging
40
40
  result = send original_method, *args
41
41
  # Below is the hack to properly escape binary data (if any manages to make it to logs)
42
- @context.test.logger.debug("LEAVE <<< #{self.class.name}::#{__callee__} => #{[result].to_s[1..-2]}") unless skip_logging
42
+ Thread.current['logger'].debug("LEAVE <<< #{self.class.name}::#{__callee__} => #{[result].to_s[1..-2]}") unless skip_logging
43
43
  result
44
44
  end
45
45
  @added = false
@@ -1,3 +1,3 @@
1
1
  module Moto
2
- VERSION = '0.0.61'
2
+ VERSION = '0.7.0'
3
3
  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.61
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bartek Wilczek
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2016-05-18 00:00:00.000000000 Z
14
+ date: 2016-05-26 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -87,6 +87,7 @@ files:
87
87
  - lib/app_generator.rb
88
88
  - lib/cli.rb
89
89
  - lib/clients/base.rb
90
+ - lib/clients/clients_manager.rb
90
91
  - lib/clients/website.rb
91
92
  - lib/config.rb
92
93
  - lib/empty_listener.rb
@@ -94,7 +95,6 @@ files:
94
95
  - lib/exceptions/test_forced_failure.rb
95
96
  - lib/exceptions/test_forced_passed.rb
96
97
  - lib/exceptions/test_skipped.rb
97
- - lib/forward_context_methods.rb
98
98
  - lib/initializer.rb
99
99
  - lib/page.rb
100
100
  - lib/parser.rb
@@ -1,19 +0,0 @@
1
- module Moto
2
- module ForwardContextMethods
3
- # Access client object instance for given class name.
4
- def client(name)
5
- @context.client(name)
6
- end
7
-
8
- # Write message to test execution log file. See Ruby Logger class for details.
9
- def logger
10
- @context.logger
11
- end
12
-
13
- # Access currently executed test
14
- def test
15
- @context.test
16
- end
17
-
18
- end
19
- end