diff --git a/Library/Homebrew/dev-cmd/test.rb b/Library/Homebrew/dev-cmd/test.rb index 1874c985d4..e97ebd7eb7 100644 --- a/Library/Homebrew/dev-cmd/test.rb +++ b/Library/Homebrew/dev-cmd/test.rb @@ -36,6 +36,7 @@ module Homebrew test_args.parse require "formula_assertions" + require "formula_free_port" args.resolved_formulae.each do |f| # Cannot test uninstalled formulae diff --git a/Library/Homebrew/formula_free_port.rb b/Library/Homebrew/formula_free_port.rb new file mode 100644 index 0000000000..894b5cf8c2 --- /dev/null +++ b/Library/Homebrew/formula_free_port.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Homebrew + module FreePort + require "socket" + + def free_port + server = TCPServer.new 0 + _, port, = server.addr + server.close + + port + end + end +end diff --git a/Library/Homebrew/test.rb b/Library/Homebrew/test.rb index 095905ba67..c14cb2517f 100644 --- a/Library/Homebrew/test.rb +++ b/Library/Homebrew/test.rb @@ -7,6 +7,7 @@ require "extend/ENV" require "timeout" require "debrew" require "formula_assertions" +require "formula_free_port" require "fcntl" require "socket" require "cli/parser" @@ -26,6 +27,7 @@ begin formula = Homebrew.args.resolved_formulae.first formula.extend(Homebrew::Assertions) + formula.extend(Homebrew::FreePort) formula.extend(Debrew::Formula) if Homebrew.args.debug? # tests can also return false to indicate failure diff --git a/Library/Homebrew/test/formula_free_port_spec.rb b/Library/Homebrew/test/formula_free_port_spec.rb new file mode 100644 index 0000000000..04320edf5d --- /dev/null +++ b/Library/Homebrew/test/formula_free_port_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require "socket" +require "formula_free_port" + +module Homebrew + describe FreePort do + include described_class + + describe "#free_port" do + # IANA suggests user port from 1024 to 49151 + # and dynamic port for 49152 to 65535 + # http://www.iana.org/assignments/port-numbers + MIN_PORT = 1024 + MAX_PORT = 65535 + + it "returns a free TCP/IP port" do + port = free_port + + expect(port).to be_between(MIN_PORT, MAX_PORT) + expect { TCPServer.new(port).close }.not_to raise_error + end + end + end +end