sauce_ruby 3.5.6

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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/bin/sauce +103 -0
  3. data/lib/childprocess/process.rb +34 -0
  4. data/lib/generators/sauce/install/install_generator.rb +54 -0
  5. data/lib/parallel_tests/cli_patch.rb +23 -0
  6. data/lib/parallel_tests/saucecucumber/runner.rb +43 -0
  7. data/lib/parallel_tests/saucerspec/runner.rb +40 -0
  8. data/lib/sauce.rb +33 -0
  9. data/lib/sauce/capybara.rb +189 -0
  10. data/lib/sauce/client.rb +40 -0
  11. data/lib/sauce/config.rb +434 -0
  12. data/lib/sauce/driver_pool.rb +5 -0
  13. data/lib/sauce/heroku.rb +18 -0
  14. data/lib/sauce/job.rb +159 -0
  15. data/lib/sauce/parallel.rb +16 -0
  16. data/lib/sauce/parallel/test_broker.rb +110 -0
  17. data/lib/sauce/parallel/test_group.rb +24 -0
  18. data/lib/sauce/railtie.rb +11 -0
  19. data/lib/sauce/raketasks.rb +83 -0
  20. data/lib/sauce/rspec/rspec.rb +186 -0
  21. data/lib/sauce/rspec/rspec_formatter.rb +20 -0
  22. data/lib/sauce/rspec/rspec_one_support.rb +66 -0
  23. data/lib/sauce/selenium.rb +95 -0
  24. data/lib/sauce/test_base.rb +21 -0
  25. data/lib/sauce/test_unit.rb +111 -0
  26. data/lib/sauce/utilities.rb +80 -0
  27. data/lib/sauce/utilities/connect.rb +45 -0
  28. data/lib/sauce/utilities/rails_server.rb +95 -0
  29. data/lib/sauce/utilities/rake.rb +32 -0
  30. data/lib/sauce/version.rb +9 -0
  31. data/lib/sauce/webmock.rb +16 -0
  32. data/lib/tasks/parallel_testing.rb +148 -0
  33. data/spec/cucumber_helper.rb +42 -0
  34. data/spec/integration/connect/spec/spec_helper.rb +21 -0
  35. data/spec/integration/connect/spec/start_tunnel_spec.rb +9 -0
  36. data/spec/integration/connect/spec/with_capybara_spec.rb +10 -0
  37. data/spec/integration/connect_integration_spec.rb +99 -0
  38. data/spec/integration/rspec-capybara/spec/capybara_required_last_spec.rb +18 -0
  39. data/spec/integration/rspec-capybara/spec/integration_spec.rb +17 -0
  40. data/spec/integration/rspec-capybara/spec/sauce_config_spec.rb +13 -0
  41. data/spec/integration/rspec-capybara/spec/sauce_required_last_spec.rb +21 -0
  42. data/spec/integration/rspec-capybara/spec/selenium/selenium_with_capybara.rb +12 -0
  43. data/spec/integration/rspec-capybara/spec/spec_helper.rb +37 -0
  44. data/spec/integration/rspec/spec/integration_spec.rb +13 -0
  45. data/spec/integration/rspec/spec/selenium/selenium_directory_spec.rb +20 -0
  46. data/spec/integration/rspec/spec/spec_helper.rb +52 -0
  47. data/spec/integration/rspec/spec/tagging/selenium_tagging_spec.rb +29 -0
  48. data/spec/integration/testunit/test/capybara_integration_test.rb +37 -0
  49. data/spec/integration/testunit/test/integration_test.rb +21 -0
  50. data/spec/integration/testunit/test/test_helper.rb +13 -0
  51. data/spec/parallel_tests/sauce_rspec_runner_spec.rb +23 -0
  52. data/spec/sauce/capybara_spec.rb +386 -0
  53. data/spec/sauce/config/browser_spec.rb +73 -0
  54. data/spec/sauce/config/config_spec.rb +400 -0
  55. data/spec/sauce/config/default_browsers_spec.rb +46 -0
  56. data/spec/sauce/config/environment_config_spec.rb +106 -0
  57. data/spec/sauce/config/load_defaults_spec.rb +50 -0
  58. data/spec/sauce/config/perfile_browser_spec.rb +105 -0
  59. data/spec/sauce/connect_spec.rb +21 -0
  60. data/spec/sauce/cucumber_spec.rb +212 -0
  61. data/spec/sauce/driver_pool_spec.rb +8 -0
  62. data/spec/sauce/file_detector_spec.rb +15 -0
  63. data/spec/sauce/jasmine_spec.rb +30 -0
  64. data/spec/sauce/parallel/test_broker_spec.rb +77 -0
  65. data/spec/sauce/selenium_spec.rb +60 -0
  66. data/spec/sauce/tasks_spec.rb +180 -0
  67. data/spec/sauce/utilities/rails_server_spec.rb +109 -0
  68. data/spec/sauce/utilities/rake_spec.rb +46 -0
  69. data/spec/sauce/utilities/utilities_spec.rb +137 -0
  70. data/spec/sauce_helper.rb +8 -0
  71. data/spec/spec_helper.rb +27 -0
  72. metadata +390 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d0e0aad8cbfd23b54304b3b5190e3af87159e509
4
+ data.tar.gz: 35a9bc2da5f12d59c72f17a06836d9c57d3310fa
5
+ SHA512:
6
+ metadata.gz: c27dc8ae6d754fdb7ae798b26f1cb02f234cf42937c3217ae585c484225cd3860f7b8ba929d9ecb0c2f9cc67f7ae8e449523ef35f1762723dcc5c89372278185
7
+ data.tar.gz: 6667deae41d668ac3c819ac9756ee9d92520ca97304921ff94b3f53dcccc88e3ff1a26439300590f2cd0a26fa308ef1454b588255a0982e277750ea786d9adcf
data/bin/sauce ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'cmdparse'
4
+ require 'yaml'
5
+ require 'fileutils'
6
+ require 'json'
7
+ require 'highline/import'
8
+
9
+ sauce_dir = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
10
+ $LOAD_PATH.unshift(sauce_dir) unless $LOAD_PATH.include?(sauce_dir)
11
+
12
+ require 'sauce'
13
+
14
+ cmd = CmdParse::CommandParser.new(true, true)
15
+ cmd.program_name = "sauce "
16
+ cmd.program_version = [0, 1, 0]
17
+
18
+ cmd.add_command(CmdParse::HelpCommand.new)
19
+
20
+ class ConnectCommand < CmdParse::Command
21
+ def usage
22
+ "Usage: #{commandparser.program_name}connect"
23
+ end
24
+ end
25
+ connect = ConnectCommand.new('connect', false)
26
+ connect.short_desc = 'Connect a Sauce Connect tunnel'
27
+ connect.set_execution_block do |args|
28
+ begin
29
+ require 'sauce/connect'
30
+ rescue LoadError
31
+ puts "Please install the sauce-connect gem (`gem install sauce-connect`) in order to use Sauce Connect"
32
+ exit 1
33
+ end
34
+ require 'sauce/config'
35
+ config = Sauce::Config.new
36
+ command = "#{Sauce::Connect.connect_command} #{config.username} #{config.access_key} #{ARGV[1 .. -1]}"
37
+ exec(command)
38
+ end
39
+ cmd.add_command(connect)
40
+
41
+
42
+ # configure
43
+ class ConfigureCommand < CmdParse::Command
44
+ def usage
45
+ "Usage: #{commandparser.program_name}configure USERNAME ACCESS_KEY"
46
+ end
47
+ end
48
+ configure = ConfigureCommand.new('configure', false)
49
+ configure.short_desc = "Configure Sauce Labs credentials"
50
+ configure.set_execution_block do |args|
51
+ if args.length < 2
52
+ puts configure.usage
53
+ exit 1
54
+ end
55
+ username = args[0]
56
+ access_key = args[1]
57
+ dir = File.join(File.expand_path("~"), ".sauce")
58
+ FileUtils.mkdir(dir) unless File.directory?(dir)
59
+
60
+ out = File.new(File.join(dir, "ondemand.yml"), 'w')
61
+ out.write(YAML.dump({"username" => username, "access_key" => access_key}))
62
+ out.close()
63
+ end
64
+ cmd.add_command(configure)
65
+
66
+ #create
67
+ create = CmdParse::Command.new('create', false)
68
+ create.short_desc = "Create a new Sauce Labs account"
69
+ create.set_execution_block do |args|
70
+ puts "Let's create a new account!"
71
+ username = ask("Username: ")
72
+ password = ask("Password: ") { |q| q.echo = "*" }
73
+ email = ask("Email: ")
74
+ name = ask("Full name: ")
75
+
76
+ body = {
77
+ :username => username,
78
+ :password => password,
79
+ :email => email,
80
+ :name => name,
81
+ :token => "c8eb3e2645005bcbbce7e2c208c6b7a71555d908"
82
+ }.to_json
83
+
84
+ begin
85
+ result = RestClient.post("http://saucelabs.com/rest/v1/users",
86
+ body, :content_type => :json, :accept => :json)
87
+ rescue => e
88
+ begin
89
+ puts "ERROR: #{JSON.load(e.response)['errors']}"
90
+ rescue
91
+ puts "ERROR: #{e.response}"
92
+ end
93
+ else
94
+ result = JSON.load(result)
95
+
96
+ puts "Account #{username} created successfully."
97
+ puts "Your access key is: #{result['access_key']}"
98
+ end
99
+ end
100
+
101
+ cmd.add_command(create)
102
+
103
+ cmd.parse
@@ -0,0 +1,34 @@
1
+ module ChildProcess
2
+ module Unix
3
+ class Process < AbstractProcess
4
+
5
+ def return_unless_timeout
6
+ lambda do |timeout|
7
+ begin
8
+ return poll_for_exit timeout
9
+ rescue TimeoutError
10
+ end
11
+ end
12
+ end
13
+
14
+ def stop(timeout = 3, signal=nil)
15
+ assert_started
16
+
17
+ unless signal.nil?
18
+ send_signal signal
19
+ return_unless_timeout.call(timeout)
20
+ end
21
+
22
+ send_term
23
+ return_unless_timeout.call(timeout)
24
+
25
+ send_kill
26
+ wait
27
+ rescue Errno::ECHILD, Errno::ESRCH
28
+ # handle race condition where process dies between timeout
29
+ # and send_kill
30
+ true
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ module Sauce
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../templates", __FILE__)
5
+
6
+ desc "Prep application for Sauce OnDemand Selenium tests"
7
+
8
+ argument :username, :type => :string, :required => false
9
+ argument :api_key, :type => :string, :required => false
10
+
11
+ def copy_rake_tasks
12
+ copy_file "sauce.rake", "lib/tasks/sauce.rake"
13
+ end
14
+
15
+ def configure_credentials
16
+ if username
17
+ system("sauce config #{username} #{api_key}")
18
+ end
19
+ end
20
+
21
+ def setup_spec
22
+ if File.directory? 'spec'
23
+ empty_directory "spec/selenium"
24
+ append_file "spec/spec_helper.rb", generate_config
25
+ end
26
+ end
27
+
28
+ def setup_test
29
+ if File.directory? 'test'
30
+ empty_directory "test/selenium"
31
+ append_file "test/test_helper.rb", generate_config
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def generate_config
38
+ return <<-CONFIG
39
+
40
+ require 'sauce'
41
+
42
+ Sauce.config do |conf|
43
+ conf[:browsers] = [
44
+ ["Windows 2003", "firefox", "3.6."]
45
+ ]
46
+ conf[:application_host] = "127.0.0.1"
47
+ conf[:application_port] = "3001"
48
+ conf[:browser_url] = "http://localhost:3001/"
49
+ end
50
+ CONFIG
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ module ParallelTests
2
+ class CLI
3
+ def run_tests_in_parallel(num_processes, options)
4
+ test_results = nil
5
+
6
+ report_time_taken do
7
+ groups = @runner.tests_in_groups(options[:files], num_processes, options)
8
+ non_empty_groups = groups.reject {|group| group.empty?}
9
+ Sauce::TestBroker.test_groups = non_empty_groups
10
+
11
+ report_number_of_tests(non_empty_groups)
12
+
13
+ test_results = execute_in_parallel(non_empty_groups, non_empty_groups.size, options) do |group|
14
+ run_tests(group, Sauce::TestBroker.group_index(group), num_processes, options)
15
+ end
16
+
17
+ report_results(test_results)
18
+ end
19
+
20
+ abort final_fail_message if any_test_failed?(test_results)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,43 @@
1
+ require "parallel_tests/cucumber/runner"
2
+
3
+ module ParallelTests
4
+ module Saucecucumber
5
+ class Runner < ParallelTests::Cucumber::Runner
6
+
7
+ def self.run_tests(test_files, process_number, num_processes, options)
8
+ options = options.dup
9
+ sanitized_test_files = test_files.map { |val| Shellwords.escape(val) }
10
+ env = Sauce::TestBroker.next_environment(test_files)
11
+ env.merge!({"AUTOTEST" => "1"}) if $stdout.tty? # display color when we are in a terminal
12
+ options.merge!({:env => env})
13
+ cmd = [
14
+ executable,
15
+ (runtime_logging if File.directory?(File.dirname(runtime_log))),
16
+ cucumber_opts(options[:test_options]),
17
+ *sanitized_test_files
18
+ ].compact.join(" ")
19
+ execute_command(cmd, process_number, num_processes, options)
20
+ end
21
+
22
+ def self.tests_in_groups(tests, num_groups, options={})
23
+ originals = (options[:group_by] == :steps) ? Grouper.by_steps(find_tests(tests, options), num_groups, options) : super
24
+ all_tests = originals.flatten * Sauce::TestBroker.test_platforms(:cucumber).length
25
+ base_group_size = all_tests.length / num_groups
26
+ num_full_groups = all_tests.length - (base_group_size * num_groups)
27
+
28
+ curpos = 0
29
+ groups = []
30
+ num_groups.times do |i|
31
+ group_size = base_group_size
32
+ if i < num_full_groups
33
+ group_size += 1
34
+ end
35
+ groups << all_tests.slice(curpos, group_size)
36
+ curpos += group_size
37
+ end
38
+
39
+ groups
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ require "yaml"
2
+ require "parallel_tests/rspec/runner"
3
+
4
+ module ParallelTests
5
+ module Saucerspec
6
+ class Runner < ParallelTests::RSpec::Runner
7
+
8
+ def self.run_tests(test_files, process_number, num_processes, options)
9
+ our_options = options.dup
10
+ exe = executable # expensive, so we cache
11
+ version = (exe =~ /\brspec\b/ ? 2 : 1)
12
+ cmd = [exe, our_options[:test_options], (rspec_2_color if version == 2), spec_opts, *test_files].compact.join(" ")
13
+ env = Sauce::TestBroker.next_environment(test_files)
14
+ env << " #{rspec_1_color}" if version == 1
15
+ our_options.merge!(:env => env)
16
+ execute_command(cmd, process_number, num_processes, our_options)
17
+ end
18
+
19
+
20
+ def self.tests_in_groups(tests, num_groups, options={})
21
+ all_tests = super.flatten * Sauce::TestBroker.test_platforms(:rspec).length
22
+ base_group_size = all_tests.length / num_groups
23
+ num_full_groups = all_tests.length - (base_group_size * num_groups)
24
+
25
+ curpos = 0
26
+ groups = []
27
+ num_groups.times do |i|
28
+ group_size = base_group_size
29
+ if i < num_full_groups
30
+ group_size += 1
31
+ end
32
+ groups << all_tests.slice(curpos, group_size)
33
+ curpos += group_size
34
+ end
35
+
36
+ groups
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/sauce.rb ADDED
@@ -0,0 +1,33 @@
1
+ if defined?(Rails)
2
+ require "sauce/railtie"
3
+ else
4
+ require 'tasks/parallel_testing'
5
+ end
6
+
7
+ require 'sauce/version'
8
+ require 'sauce/utilities'
9
+ require 'sauce/utilities/rake'
10
+ require 'sauce/job'
11
+ require 'sauce/client'
12
+ require 'sauce/config'
13
+ require 'sauce/selenium'
14
+ require 'sauce/test_base'
15
+ require 'sauce/rspec/rspec'
16
+ require 'sauce/test_unit'
17
+ require 'parallel_tests/saucerspec/runner'
18
+ require 'parallel_tests/saucecucumber/runner'
19
+
20
+
21
+ # Ruby before 1.9.3-p382 does not handle exit codes correctly when nested
22
+ if RUBY_VERSION == "1.9.3" && RUBY_PATCHLEVEL < 392
23
+ module Kernel
24
+ alias :existing_at_exit :at_exit
25
+ def at_exit(&block)
26
+ existing_at_exit do
27
+ exit_status = $!.status if $!.is_a?(SystemExit)
28
+ block.call
29
+ exit exit_status if exit_status
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,189 @@
1
+ require 'capybara'
2
+ require 'sauce/config'
3
+ require 'sauce/selenium'
4
+ require 'sauce/version'
5
+
6
+
7
+ $sauce_tunnel = nil
8
+
9
+ module Sauce
10
+ module Capybara
11
+ class Driver < ::Capybara::Selenium::Driver
12
+ RETRY_ON = [::Selenium::WebDriver::Error::UnhandledError,
13
+ ::Selenium::WebDriver::Error::UnknownError]
14
+ MAX_RETRIES = 3
15
+
16
+ def handle_retry(method, *args, &block)
17
+ retries = 0
18
+
19
+ # Disable retries only when we really really want to, this will remain
20
+ # an undocomented hack for the time being
21
+ if ENV['SAUCE_DISABLE_RETRY']
22
+ retries = MAX_RETRIES
23
+ end
24
+
25
+ begin
26
+ send("base_#{method}".to_sym, *args, &block)
27
+ rescue *RETRY_ON => e
28
+ if retries < MAX_RETRIES
29
+ puts "Received an exception (#{e}), retrying"
30
+ retries = retries + 1
31
+ retry
32
+ else
33
+ raise
34
+ end
35
+ end
36
+ end
37
+
38
+ alias :base_visit :visit
39
+ alias :base_current_url :current_url
40
+ alias :base_within_frame :within_frame
41
+ alias :base_within_window :within_window
42
+ alias :base_find_window :find_window
43
+ alias :base_execute_script :execute_script
44
+ alias :base_evaluate_script :evaluate_script
45
+
46
+ @methods_to_retry = [:visit, :current_url,
47
+ :within_frame, :within_window, :find_window, :source,
48
+ :execute_script, :evaluate_script
49
+ ]
50
+
51
+ if method_defined? :find
52
+ alias :base_find :find
53
+ @methods_to_retry += [:find]
54
+ else
55
+ alias :base_find_css :find_css
56
+ alias :base_find_xpath :find_xpath
57
+ @methods_to_retry += [:find_css, :find_xpath]
58
+ end
59
+
60
+ if Gem::Version.new(::Capybara::VERSION) < Gem::Version.new(2)
61
+ alias :base_body :body
62
+ alias :base_source :source
63
+
64
+ @methods_to_retry + [:body, :source]
65
+ else
66
+ alias :base_html :html
67
+ @methods_to_retry + [:html]
68
+ end
69
+
70
+ @methods_to_retry.each do |method|
71
+ define_method(method) do |*args, &block|
72
+ handle_retry(method, *args, &block)
73
+ end
74
+ end
75
+
76
+ # Oh gods why didn't I comment these when I wrote them?
77
+ # These are what I think I'm doing.
78
+ #
79
+ # Returns the browser currently being used or fetches a new
80
+ # browser, either from the RSpec integration or by creating
81
+ # one.
82
+ def browser
83
+ # Return the existing browser if we have it
84
+ unless existing_browser?
85
+ # Try to get a driver from the driver pool
86
+ @browser = rspec_browser
87
+ unless @browser
88
+ @browser = Sauce::Selenium2.new
89
+ at_exit do
90
+ finish!
91
+ end
92
+ end
93
+ end
94
+ @browser
95
+ end
96
+
97
+ # Returns the rspec created browser if it exists
98
+ def rspec_browser
99
+ if browser = Sauce.driver_pool[Thread.current.object_id]
100
+ @using_rspec_browser = true
101
+ else
102
+ @using_rspec_browser = false
103
+ end
104
+ browser
105
+ end
106
+
107
+ # If a browser has been created OR RSpec has put one in the diriver pool
108
+ # and we're using that browser, returns true.
109
+ def existing_browser?
110
+ if @using_rspec_browser
111
+ @browser == Sauce.driver_pool[Thread.current.object_id]
112
+ else
113
+ @browser
114
+ end
115
+ end
116
+
117
+ def finish!
118
+ @browser.quit if existing_browser?
119
+ @browser = nil
120
+
121
+ # Rethink how to do this. RSpec still references the driver pool.
122
+ Sauce.driver_pool[Thread.current.object_id] = nil
123
+ @using_rspec_browser = nil
124
+ end
125
+
126
+ def render(path)
127
+ browser.save_screenshot path
128
+ end
129
+ end
130
+
131
+ def self.configure_capybara
132
+ ::Capybara.configure do |config|
133
+ if Sauce::Config.new[:start_local_application]
134
+ config.server_port = Sauce::Config.get_application_port
135
+ end
136
+ begin
137
+ #config.always_include_port = true
138
+ rescue
139
+ # This option is only in Capybara 2+
140
+ end
141
+ end
142
+ end
143
+
144
+ def self.configure_capybara_for_rspec
145
+ begin
146
+ require "rspec/core"
147
+ ::RSpec.configure do |config|
148
+ config.before :suite do
149
+ ::Capybara.configure do |capy_config|
150
+ sauce_config = Sauce::Config.new
151
+ if capy_config.app_host.nil?
152
+ if sauce_config[:start_local_application]
153
+ host = sauce_config[:application_host] || "127.0.0.1"
154
+ port = sauce_config[:application_port]
155
+ capy_config.app_host = "http://#{host}:#{port}"
156
+ capy_config.run_server = false
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ rescue LoadError => e
163
+ # User is not using RSpec
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ Capybara.register_driver :sauce do |app|
170
+ driver = Sauce::Capybara::Driver.new(app)
171
+ end
172
+
173
+ Sauce::Capybara.configure_capybara
174
+
175
+ # Monkeypatch Capybara to not use :selenium driver
176
+ require 'capybara/dsl'
177
+ module Capybara
178
+ def self.javascript_driver
179
+ @javascript_driver || :sauce
180
+ end
181
+ end
182
+
183
+ module Sauce
184
+ module RSpec
185
+ module SeleniumExampleGroup
186
+ Sauce::Capybara.configure_capybara_for_rspec
187
+ end
188
+ end
189
+ end