I\'d like to test the HTTP API of our Rails app using Faraday and RSpec. Faraday needs the host url + port. Unfortunately the port of the testing environment does always cha
There's probably more than one way to do this, but this is working for me right now:
port = `lsof -p #{Process.pid} -ai TCP -as TCP:LISTEN -Fn | grep ^n | cut -c 4- | uniq`.strip
Note that you'll have to do this at some point after the app has loaded - i.e., you can't use this in your environment.rb
or application.rb
file.
Basically what this command does is as follows:
lsof
is the Unix command for LiSt Open Files-p #{Process.pid}
limits it to the current process (i.e., your test web server instance)-ai TCP
limits it to "files" of type TCP (i.e., open TCP ports). (Note: the -a
is to make it AND the search with the pid one - the default, using just -i
would OR the search)-as TCP:LISTEN
limits to just TCP ports that are being listened on (as opposed to any open port - like your app's connection to Postgres for example)-Fn
tells it to only output the "name" column, which in this case will be the IP/port that is being listened onThe output of that part by itself will be something like this:
p12345
n*:5001
n*:5001
The first line, starting with p
is the process ID. There's no way to suppress this.
The next 2 lines (not sure why it can output multiples, but we'll take care of it in a minute) are the "name" column (hence n
), followed by the IP + port. In our case (and I imagine yours as well, in a test environment), the web server listens on all available local IPs, thus *
. Then it tells us that the port is, in this case 5001.
Finally, we pipe it through...
* grep ^n
to eliminate the first line (the process id)
* cut
to say "cut from columns 4 on" - i.e., remove the n*:
to return just the port, and
* uniq
to just get the one instance
(It will also have a trailing newline, thus the strip
call.)
In my case, I'm using this in my Cucumber env.rb
thusly, to reconfigure the URL options for ActiveMailer so my email links get generated properly as working links in test:
port = lsof -p #{Process.pid} -ai TCP -as TCP:LISTEN -Fn | grep ^n | cut -c 4- | uniq
.strip
MyApp::Application.configure do config.action_mailer.default_url_options[:host] = "0.0.0.0:#{port}" end
No doubt you could do the same thing in a helper/config for Rspec as well.
If using Capybara you can set the port in the spec_helper.rb like so:
Capybara.server_port = 1234
See also: https://github.com/jnicklas/capybara/pull/123