| 
									
										
										
										
											2024-06-30 19:30:35 +01:00
										 |  |  | # typed: strict | 
					
						
							| 
									
										
										
										
											2019-04-19 15:38:03 +09:00
										 |  |  | # frozen_string_literal: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  | require "abstract_command" | 
					
						
							| 
									
										
										
										
											2014-06-19 17:57:36 -05:00
										 |  |  | require "extend/ENV" | 
					
						
							| 
									
										
										
										
											2015-04-13 18:05:41 +08:00
										 |  |  | require "sandbox" | 
					
						
							| 
									
										
										
										
											2015-04-21 16:59:23 +08:00
										 |  |  | require "timeout" | 
					
						
							| 
									
										
										
										
											2012-03-12 21:21:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-18 22:41:47 -05:00
										 |  |  | module Homebrew | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |   module DevCmd | 
					
						
							|  |  |  |     class Test < AbstractCommand | 
					
						
							|  |  |  |       cmd_args do | 
					
						
							|  |  |  |         description <<~EOS | 
					
						
							|  |  |  |           Run the test method provided by an installed formula. | 
					
						
							|  |  |  |           There is no standard output or return code, but generally it should notify the | 
					
						
							|  |  |  |           user if something is wrong with the installed formula. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           *Example:* `brew install jruby && brew test jruby` | 
					
						
							|  |  |  |         EOS | 
					
						
							|  |  |  |         switch "-f", "--force", | 
					
						
							|  |  |  |                description: "Test formulae even if they are unlinked." | 
					
						
							|  |  |  |         switch "--HEAD", | 
					
						
							|  |  |  |                description: "Test the HEAD version of a formula." | 
					
						
							|  |  |  |         switch "--keep-tmp", | 
					
						
							|  |  |  |                description: "Retain the temporary files created for the test." | 
					
						
							|  |  |  |         switch "--retry", | 
					
						
							|  |  |  |                description: "Retry if a testing fails." | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         named_args :installed_formula, min: 1, without_api: true | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2019-03-27 11:49:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |       sig { override.void } | 
					
						
							|  |  |  |       def run | 
					
						
							|  |  |  |         Homebrew.install_bundler_gems!(groups: ["formula_test"], setup_path: false) | 
					
						
							| 
									
										
										
										
											2021-02-24 18:01:47 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |         require "formula_assertions" | 
					
						
							|  |  |  |         require "formula_free_port" | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  |         require "utils/fork" | 
					
						
							| 
									
										
										
										
											2019-03-27 11:49:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |         args.named.to_resolved_formulae.each do |f| | 
					
						
							|  |  |  |           # Cannot test uninstalled formulae | 
					
						
							|  |  |  |           unless f.latest_version_installed? | 
					
						
							|  |  |  |             ofail "Testing requires the latest version of #{f.full_name}" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-03-10 21:28:49 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |           # Cannot test formulae without a test method | 
					
						
							|  |  |  |           unless f.test_defined? | 
					
						
							|  |  |  |             ofail "#{f.full_name} defines no test" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2011-03-10 21:28:49 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |           # Don't test unlinked formulae | 
					
						
							|  |  |  |           if !args.force? && !f.keg_only? && !f.linked? | 
					
						
							|  |  |  |             ofail "#{f.full_name} is not linked" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2017-06-23 17:42:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |           # Don't test formulae missing test dependencies | 
					
						
							|  |  |  |           missing_test_deps = f.recursive_dependencies do |dependent, dependency| | 
					
						
							|  |  |  |             Dependency.prune if dependency.installed? | 
					
						
							|  |  |  |             next if dependency.test? && dependent == f | 
					
						
							| 
									
										
										
										
											2018-09-17 02:45:00 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |             Dependency.prune unless dependency.required? | 
					
						
							|  |  |  |           end.map(&:to_s) | 
					
						
							|  |  |  |           unless missing_test_deps.empty? | 
					
						
							|  |  |  |             ofail "#{f.full_name} is missing test dependencies: #{missing_test_deps.join(" ")}" | 
					
						
							|  |  |  |             next | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2018-03-05 10:36:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |           oh1 "Testing #{f.full_name}" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           env = ENV.to_hash | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           begin | 
					
						
							|  |  |  |             exec_args = HOMEBREW_RUBY_EXEC_ARGS + %W[
 | 
					
						
							|  |  |  |               -- | 
					
						
							|  |  |  |               #{HOMEBREW_LIBRARY_PATH}/test.rb | 
					
						
							|  |  |  |               #{f.path} | 
					
						
							|  |  |  |             ].concat(args.options_only) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             exec_args << "--HEAD" if f.head? | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-28 03:45:26 +01:00
										 |  |  |             if Sandbox.available? | 
					
						
							|  |  |  |               sandbox = Sandbox.new | 
					
						
							|  |  |  |               f.logs.mkpath | 
					
						
							|  |  |  |               sandbox.record_log(f.logs/"test.sandbox.log") | 
					
						
							|  |  |  |               sandbox.allow_write_temp_and_cache | 
					
						
							|  |  |  |               sandbox.allow_write_log(f) | 
					
						
							|  |  |  |               sandbox.allow_write_xcode | 
					
						
							|  |  |  |               sandbox.allow_write_path(HOMEBREW_PREFIX/"var/cache") | 
					
						
							|  |  |  |               sandbox.allow_write_path(HOMEBREW_PREFIX/"var/homebrew/locks") | 
					
						
							|  |  |  |               sandbox.allow_write_path(HOMEBREW_PREFIX/"var/log") | 
					
						
							|  |  |  |               sandbox.allow_write_path(HOMEBREW_PREFIX/"var/run") | 
					
						
							|  |  |  |               sandbox.deny_all_network unless f.class.network_access_allowed?(:test) | 
					
						
							|  |  |  |               sandbox.run(*exec_args) | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |               Utils.safe_fork do | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |                 exec(*exec_args) | 
					
						
							|  |  |  |               end | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2025-01-12 16:56:48 +00:00
										 |  |  |           # Rescue any possible exception types. | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |           rescue Exception => e # rubocop:disable Lint/RescueException | 
					
						
							| 
									
										
										
										
											2024-04-01 12:09:20 -07:00
										 |  |  |             retry if retry_test?(f) | 
					
						
							| 
									
										
										
										
											2024-07-14 08:49:39 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |             require "utils/backtrace" | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |             ofail "#{f.full_name}: failed" | 
					
						
							|  |  |  |             $stderr.puts e, Utils::Backtrace.clean(e) | 
					
						
							|  |  |  |           ensure | 
					
						
							|  |  |  |             ENV.replace(env) | 
					
						
							| 
									
										
										
										
											2015-04-13 18:05:41 +08:00
										 |  |  |           end | 
					
						
							| 
									
										
										
										
											2013-06-04 20:34:34 +01:00
										 |  |  |         end | 
					
						
							| 
									
										
										
										
											2011-03-10 21:28:49 -08:00
										 |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-29 12:00:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |       private | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-30 19:30:35 +01:00
										 |  |  |       sig { params(formula: Formula).returns(T::Boolean) } | 
					
						
							| 
									
										
										
										
											2024-04-01 12:09:20 -07:00
										 |  |  |       def retry_test?(formula) | 
					
						
							| 
									
										
										
										
											2024-06-30 19:30:35 +01:00
										 |  |  |         @test_failed ||= T.let(Set.new, T.nilable(T::Set[T.untyped])) | 
					
						
							| 
									
										
										
										
											2024-03-21 21:52:32 -07:00
										 |  |  |         if args.retry? && @test_failed.add?(formula) | 
					
						
							|  |  |  |           oh1 "Testing #{formula.full_name} (again)" | 
					
						
							|  |  |  |           formula.clear_cache | 
					
						
							|  |  |  |           ENV["RUST_BACKTRACE"] = "full" | 
					
						
							|  |  |  |           true | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |           Homebrew.failed = true | 
					
						
							|  |  |  |           false | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							| 
									
										
										
										
											2020-07-29 12:00:45 +01:00
										 |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							| 
									
										
										
										
											2011-03-10 21:28:49 -08:00
										 |  |  | end |