
This is more in keeping with the other DSL methods and Ruby convention along with the fact that these socket names are just used internally by launchd.
1145 lines
33 KiB
Ruby
1145 lines
33 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "formula"
|
|
require "service"
|
|
|
|
describe Homebrew::Service do
|
|
let(:name) { "formula_name" }
|
|
|
|
def stub_formula(&block)
|
|
formula(name) do
|
|
url "https://brew.sh/test-1.0.tbz"
|
|
|
|
instance_eval(&block) if block
|
|
end
|
|
end
|
|
|
|
def stub_formula_with_service_sockets(sockets_var)
|
|
stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
sockets sockets_var
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#std_service_path_env" do
|
|
it "returns valid std_service_path_env" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :immediate
|
|
environment_variables PATH: std_service_path_env
|
|
error_log_path var/"log/beanstalkd.error.log"
|
|
log_path var/"log/beanstalkd.log"
|
|
working_dir var
|
|
keep_alive true
|
|
end
|
|
end
|
|
|
|
path = f.service.std_service_path_env
|
|
expect(path).to eq("#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin")
|
|
end
|
|
end
|
|
|
|
describe "#process_type" do
|
|
it "throws for unexpected type" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
process_type :cow
|
|
end
|
|
end
|
|
|
|
expect do
|
|
f.service.manual_command
|
|
end.to raise_error TypeError, "Service#process_type allows: 'background'/'standard'/'interactive'/'adaptive'"
|
|
end
|
|
end
|
|
|
|
describe "#keep_alive" do
|
|
it "throws for unexpected keys" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
keep_alive test: "key"
|
|
end
|
|
end
|
|
|
|
expect do
|
|
f.service.manual_command
|
|
end.to raise_error TypeError, "Service#keep_alive allows only [:always, :successful_exit, :crashed, :path]"
|
|
end
|
|
end
|
|
|
|
describe "#requires_root?" do
|
|
it "returns status when set" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
require_root true
|
|
end
|
|
end
|
|
|
|
expect(f.service.requires_root?).to be(true)
|
|
end
|
|
|
|
it "returns status when not set" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
end
|
|
end
|
|
|
|
expect(f.service.requires_root?).to be(false)
|
|
end
|
|
end
|
|
|
|
describe "#run_type" do
|
|
it "throws for unexpected type" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :cow
|
|
end
|
|
end
|
|
|
|
expect do
|
|
f.service.manual_command
|
|
end.to raise_error TypeError, "Service#run_type allows: 'immediate'/'interval'/'cron'"
|
|
end
|
|
end
|
|
|
|
describe "#sockets" do
|
|
let(:sockets_type_error_message) { "Service#sockets a formatted socket definition as <type>://<host>:<port>" }
|
|
|
|
it "throws for missing type" do
|
|
[
|
|
stub_formula_with_service_sockets("127.0.0.1:80"),
|
|
stub_formula_with_service_sockets({ "Socket" => "127.0.0.1:80" }),
|
|
].each do |f|
|
|
expect { f.service.manual_command }.to raise_error TypeError, sockets_type_error_message
|
|
end
|
|
end
|
|
|
|
it "throws for missing host" do
|
|
[
|
|
stub_formula_with_service_sockets("tcp://:80"),
|
|
stub_formula_with_service_sockets({ "Socket" => "tcp://:80" }),
|
|
].each do |f|
|
|
expect { f.service.manual_command }.to raise_error TypeError, sockets_type_error_message
|
|
end
|
|
end
|
|
|
|
it "throws for missing port" do
|
|
[
|
|
stub_formula_with_service_sockets("tcp://127.0.0.1"),
|
|
stub_formula_with_service_sockets({ "Socket" => "tcp://127.0.0.1" }),
|
|
].each do |f|
|
|
expect { f.service.manual_command }.to raise_error TypeError, sockets_type_error_message
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#manual_command" do
|
|
it "returns valid manual_command" do
|
|
f = stub_formula do
|
|
service do
|
|
run "#{HOMEBREW_PREFIX}/bin/beanstalkd"
|
|
run_type :immediate
|
|
environment_variables PATH: std_service_path_env, ETC_DIR: etc/"beanstalkd"
|
|
error_log_path var/"log/beanstalkd.error.log"
|
|
log_path var/"log/beanstalkd.log"
|
|
working_dir var
|
|
keep_alive true
|
|
end
|
|
end
|
|
|
|
path = f.service.manual_command
|
|
expect(path).to eq("ETC_DIR=\"#{HOMEBREW_PREFIX}/etc/beanstalkd\" #{HOMEBREW_PREFIX}/bin/beanstalkd")
|
|
end
|
|
|
|
it "returns valid manual_command without variables" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :immediate
|
|
environment_variables PATH: std_service_path_env
|
|
error_log_path var/"log/beanstalkd.error.log"
|
|
log_path var/"log/beanstalkd.log"
|
|
working_dir var
|
|
keep_alive true
|
|
end
|
|
end
|
|
|
|
path = f.service.manual_command
|
|
expect(path).to eq("#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd")
|
|
end
|
|
end
|
|
|
|
describe "#to_plist" do
|
|
it "returns valid plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
environment_variables PATH: std_service_path_env, FOO: "BAR", ETC_DIR: etc/"beanstalkd"
|
|
error_log_path var/"log/beanstalkd.error.log"
|
|
log_path var/"log/beanstalkd.log"
|
|
input_path var/"in/beanstalkd"
|
|
require_root true
|
|
root_dir var
|
|
working_dir var
|
|
keep_alive true
|
|
launch_only_once true
|
|
process_type :interactive
|
|
restart_delay 30
|
|
interval 5
|
|
macos_legacy_timers true
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>EnvironmentVariables</key>
|
|
\t<dict>
|
|
\t\t<key>ETC_DIR</key>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/etc/beanstalkd</string>
|
|
\t\t<key>FOO</key>
|
|
\t\t<string>BAR</string>
|
|
\t\t<key>PATH</key>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
\t</dict>
|
|
\t<key>KeepAlive</key>
|
|
\t<true/>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LaunchOnlyOnce</key>
|
|
\t<true/>
|
|
\t<key>LegacyTimers</key>
|
|
\t<true/>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProcessType</key>
|
|
\t<string>Interactive</string>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t\t<string>test</string>
|
|
\t</array>
|
|
\t<key>RootDirectory</key>
|
|
\t<string>#{HOMEBREW_PREFIX}/var</string>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
\t<key>StandardErrorPath</key>
|
|
\t<string>#{HOMEBREW_PREFIX}/var/log/beanstalkd.error.log</string>
|
|
\t<key>StandardInPath</key>
|
|
\t<string>#{HOMEBREW_PREFIX}/var/in/beanstalkd</string>
|
|
\t<key>StandardOutPath</key>
|
|
\t<string>#{HOMEBREW_PREFIX}/var/log/beanstalkd.log</string>
|
|
\t<key>TimeOut</key>
|
|
\t<integer>30</integer>
|
|
\t<key>WorkingDirectory</key>
|
|
\t<string>#{HOMEBREW_PREFIX}/var</string>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid plist with socket" do
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
\t<key>Sockets</key>
|
|
\t<dict>
|
|
\t\t<key>listeners</key>
|
|
\t\t<dict>
|
|
\t\t\t<key>SockFamily</key>
|
|
\t\t\t<string>IPv4v6</string>
|
|
\t\t\t<key>SockNodeName</key>
|
|
\t\t\t<string>127.0.0.1</string>
|
|
\t\t\t<key>SockProtocol</key>
|
|
\t\t\t<string>TCP</string>
|
|
\t\t\t<key>SockServiceName</key>
|
|
\t\t\t<string>80</string>
|
|
\t\t</dict>
|
|
\t</dict>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
|
|
[
|
|
stub_formula_with_service_sockets("tcp://127.0.0.1:80"),
|
|
stub_formula_with_service_sockets({ listeners: "tcp://127.0.0.1:80" }),
|
|
].each do |f|
|
|
plist = f.service.to_plist
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
end
|
|
|
|
it "returns valid plist with multiple sockets" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
sockets socket: "tcp://0.0.0.0:80", socket_tls: "tcp://0.0.0.0:443"
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t\t<string>test</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
\t<key>Sockets</key>
|
|
\t<dict>
|
|
\t\t<key>socket</key>
|
|
\t\t<dict>
|
|
\t\t\t<key>SockFamily</key>
|
|
\t\t\t<string>IPv4v6</string>
|
|
\t\t\t<key>SockNodeName</key>
|
|
\t\t\t<string>0.0.0.0</string>
|
|
\t\t\t<key>SockProtocol</key>
|
|
\t\t\t<string>TCP</string>
|
|
\t\t\t<key>SockServiceName</key>
|
|
\t\t\t<string>80</string>
|
|
\t\t</dict>
|
|
\t\t<key>socket_tls</key>
|
|
\t\t<dict>
|
|
\t\t\t<key>SockFamily</key>
|
|
\t\t\t<string>IPv4v6</string>
|
|
\t\t\t<key>SockNodeName</key>
|
|
\t\t\t<string>0.0.0.0</string>
|
|
\t\t\t<key>SockProtocol</key>
|
|
\t\t\t<string>TCP</string>
|
|
\t\t\t<key>SockServiceName</key>
|
|
\t\t\t<string>443</string>
|
|
\t\t</dict>
|
|
\t</dict>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid partial plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid partial plist with run_at_load being false" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :immediate
|
|
run_at_load false
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<false/>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid interval plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :interval
|
|
interval 5
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
\t<key>StartInterval</key>
|
|
\t<integer>5</integer>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid cron plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :cron
|
|
cron "@daily"
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
\t<key>StartCalendarInterval</key>
|
|
\t<dict>
|
|
\t\t<key>Hour</key>
|
|
\t\t<integer>0</integer>
|
|
\t\t<key>Minute</key>
|
|
\t\t<integer>0</integer>
|
|
\t</dict>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid keepalive-exit plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
keep_alive successful_exit: false
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>KeepAlive</key>
|
|
\t<dict>
|
|
\t\t<key>SuccessfulExit</key>
|
|
\t\t<false/>
|
|
\t</dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid keepalive-crashed plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
keep_alive crashed: true
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>KeepAlive</key>
|
|
\t<dict>
|
|
\t\t<key>Crashed</key>
|
|
\t\t<true/>
|
|
\t</dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "returns valid keepalive-path plist" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
keep_alive path: opt_pkgshare/"test-path"
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>KeepAlive</key>
|
|
\t<dict>
|
|
\t\t<key>PathState</key>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/share/formula_name/test-path</string>
|
|
\t</dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
|
|
it "expands paths" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_sbin/"sleepwatcher", "-V", "-s", "~/.sleep", "-w", "~/.wakeup"]
|
|
working_dir "~"
|
|
end
|
|
end
|
|
|
|
plist = f.service.to_plist
|
|
plist_expect = <<~EOS
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
\t<key>Label</key>
|
|
\t<string>homebrew.mxcl.formula_name</string>
|
|
\t<key>LimitLoadToSessionType</key>
|
|
\t<array>
|
|
\t\t<string>Aqua</string>
|
|
\t\t<string>Background</string>
|
|
\t\t<string>LoginWindow</string>
|
|
\t\t<string>StandardIO</string>
|
|
\t\t<string>System</string>
|
|
\t</array>
|
|
\t<key>ProgramArguments</key>
|
|
\t<array>
|
|
\t\t<string>#{HOMEBREW_PREFIX}/opt/formula_name/sbin/sleepwatcher</string>
|
|
\t\t<string>-V</string>
|
|
\t\t<string>-s</string>
|
|
\t\t<string>#{Dir.home}/.sleep</string>
|
|
\t\t<string>-w</string>
|
|
\t\t<string>#{Dir.home}/.wakeup</string>
|
|
\t</array>
|
|
\t<key>RunAtLoad</key>
|
|
\t<true/>
|
|
\t<key>WorkingDirectory</key>
|
|
\t<string>#{Dir.home}</string>
|
|
</dict>
|
|
</plist>
|
|
EOS
|
|
expect(plist).to eq(plist_expect)
|
|
end
|
|
end
|
|
|
|
describe "#to_systemd_unit" do
|
|
it "returns valid unit" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
environment_variables PATH: std_service_path_env, FOO: "BAR"
|
|
error_log_path var/"log/beanstalkd.error.log"
|
|
log_path var/"log/beanstalkd.log"
|
|
input_path var/"in/beanstalkd"
|
|
require_root true
|
|
root_dir var
|
|
working_dir var
|
|
keep_alive true
|
|
process_type :interactive
|
|
restart_delay 30
|
|
macos_legacy_timers true
|
|
end
|
|
end
|
|
|
|
unit = f.service.to_systemd_unit
|
|
std_path = "#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
unit_expect = <<~EOS
|
|
[Unit]
|
|
Description=Homebrew generated unit for formula_name
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd test
|
|
Restart=always
|
|
RestartSec=30
|
|
WorkingDirectory=#{HOMEBREW_PREFIX}/var
|
|
RootDirectory=#{HOMEBREW_PREFIX}/var
|
|
StandardInput=file:#{HOMEBREW_PREFIX}/var/in/beanstalkd
|
|
StandardOutput=append:#{HOMEBREW_PREFIX}/var/log/beanstalkd.log
|
|
StandardError=append:#{HOMEBREW_PREFIX}/var/log/beanstalkd.error.log
|
|
Environment="PATH=#{std_path}"
|
|
Environment="FOO=BAR"
|
|
EOS
|
|
expect(unit).to eq(unit_expect.strip)
|
|
end
|
|
|
|
it "returns valid partial oneshot unit" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :immediate
|
|
launch_only_once true
|
|
end
|
|
end
|
|
|
|
unit = f.service.to_systemd_unit
|
|
unit_expect = <<~EOS
|
|
[Unit]
|
|
Description=Homebrew generated unit for formula_name
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd
|
|
EOS
|
|
expect(unit).to eq(unit_expect.strip)
|
|
end
|
|
|
|
it "expands paths" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
working_dir "~"
|
|
end
|
|
end
|
|
|
|
unit = f.service.to_systemd_unit
|
|
unit_expect = <<~EOS
|
|
[Unit]
|
|
Description=Homebrew generated unit for formula_name
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd
|
|
WorkingDirectory=#{Dir.home}
|
|
EOS
|
|
expect(unit).to eq(unit_expect.strip)
|
|
end
|
|
end
|
|
|
|
describe "#to_systemd_timer" do
|
|
it "returns valid timer" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
run_type :interval
|
|
interval 5
|
|
end
|
|
end
|
|
|
|
unit = f.service.to_systemd_timer
|
|
unit_expect = <<~EOS
|
|
[Unit]
|
|
Description=Homebrew generated timer for formula_name
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
|
|
[Timer]
|
|
Unit=homebrew.formula_name
|
|
OnUnitActiveSec=5
|
|
EOS
|
|
expect(unit).to eq(unit_expect.strip)
|
|
end
|
|
|
|
it "returns valid partial timer" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
unit = f.service.to_systemd_timer
|
|
unit_expect = <<~EOS
|
|
[Unit]
|
|
Description=Homebrew generated timer for formula_name
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
|
|
[Timer]
|
|
Unit=homebrew.formula_name
|
|
EOS
|
|
expect(unit).to eq(unit_expect)
|
|
end
|
|
|
|
it "throws on incomplete cron" do
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :cron
|
|
cron "1 2 3 4"
|
|
end
|
|
end
|
|
|
|
expect do
|
|
f.service.to_systemd_timer
|
|
end.to raise_error TypeError, "Service#parse_cron expects a valid cron syntax"
|
|
end
|
|
|
|
it "returns valid cron timers" do
|
|
styles = {
|
|
"@hourly": "*-*-*-* *:00:00",
|
|
"@daily": "*-*-*-* 00:00:00",
|
|
"@weekly": "0-*-*-* 00:00:00",
|
|
"@monthly": "*-*-*-1 00:00:00",
|
|
"@yearly": "*-*-1-1 00:00:00",
|
|
"@annually": "*-*-1-1 00:00:00",
|
|
"5 5 5 5 5": "5-*-5-5 05:05:00",
|
|
}
|
|
|
|
styles.each do |cron, calendar|
|
|
f = stub_formula do
|
|
service do
|
|
run opt_bin/"beanstalkd"
|
|
run_type :cron
|
|
cron cron.to_s
|
|
end
|
|
end
|
|
|
|
unit = f.service.to_systemd_timer
|
|
unit_expect = <<~EOS
|
|
[Unit]
|
|
Description=Homebrew generated timer for formula_name
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
|
|
[Timer]
|
|
Unit=homebrew.formula_name
|
|
Persistent=true
|
|
OnCalendar=#{calendar}
|
|
EOS
|
|
expect(unit).to eq(unit_expect.chomp)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#timed?" do
|
|
it "returns false for immediate" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
expect(f.service.timed?).to be(false)
|
|
end
|
|
|
|
it "returns true for interval" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
run_type :interval
|
|
end
|
|
end
|
|
|
|
expect(f.service.timed?).to be(true)
|
|
end
|
|
end
|
|
|
|
describe "#keep_alive?" do
|
|
it "returns true when keep_alive set to hash" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
keep_alive crashed: true
|
|
end
|
|
end
|
|
|
|
expect(f.service.keep_alive?).to be(true)
|
|
end
|
|
|
|
it "returns true when keep_alive set to true" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
keep_alive true
|
|
end
|
|
end
|
|
|
|
expect(f.service.keep_alive?).to be(true)
|
|
end
|
|
|
|
it "returns false when keep_alive not set" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
end
|
|
end
|
|
|
|
expect(f.service.keep_alive?).to be(false)
|
|
end
|
|
|
|
it "returns false when keep_alive set to false" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
keep_alive false
|
|
end
|
|
end
|
|
|
|
expect(f.service.keep_alive?).to be(false)
|
|
end
|
|
end
|
|
|
|
describe "#command" do
|
|
it "returns @run data" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"])
|
|
end
|
|
|
|
it "returns @run data on Linux", :needs_linux do
|
|
f = stub_formula do
|
|
service do
|
|
run linux: [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"])
|
|
end
|
|
|
|
it "returns nil on Linux", :needs_linux do
|
|
f = stub_formula do
|
|
service do
|
|
run macos: [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to be_nil
|
|
end
|
|
|
|
it "returns @run data on macOS", :needs_macos do
|
|
f = stub_formula do
|
|
service do
|
|
run macos: [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"])
|
|
end
|
|
|
|
it "returns nil on macOS", :needs_macos do
|
|
f = stub_formula do
|
|
service do
|
|
run linux: [opt_bin/"beanstalkd", "test"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to be_nil
|
|
end
|
|
|
|
it "returns appropriate @run data on Linux", :needs_linux do
|
|
f = stub_formula do
|
|
service do
|
|
run macos: [opt_bin/"beanstalkd", "test", "macos"], linux: [opt_bin/"beanstalkd", "test", "linux"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test", "linux"])
|
|
end
|
|
|
|
it "returns appropriate @run data on macOS", :needs_macos do
|
|
f = stub_formula do
|
|
service do
|
|
run macos: [opt_bin/"beanstalkd", "test", "macos"], linux: [opt_bin/"beanstalkd", "test", "linux"]
|
|
run_type :immediate
|
|
end
|
|
end
|
|
|
|
command = f.service.command
|
|
expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test", "macos"])
|
|
end
|
|
end
|
|
|
|
describe "#serialize" do
|
|
let(:serialized_hash) do
|
|
{
|
|
environment_variables: {
|
|
PATH: "$HOMEBREW_PREFIX/bin:$HOMEBREW_PREFIX/sbin:/usr/bin:/bin:/usr/sbin:/sbin",
|
|
},
|
|
run: [Pathname("$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd"), "test"],
|
|
run_type: :immediate,
|
|
working_dir: "/$HOME",
|
|
cron: "0 0 * * 0",
|
|
sockets: { listeners: "tcp://0.0.0.0:80" },
|
|
}
|
|
end
|
|
|
|
# @note The calls to `Formula.generating_hash!` and `Formula.generated_hash!`
|
|
# are not idempotent so they can only be used in one test.
|
|
it "replaces local paths with placeholders" do
|
|
f = stub_formula do
|
|
service do
|
|
run [opt_bin/"beanstalkd", "test"]
|
|
environment_variables PATH: std_service_path_env
|
|
working_dir Dir.home
|
|
cron "@weekly"
|
|
sockets "tcp://0.0.0.0:80"
|
|
end
|
|
end
|
|
|
|
Formula.generating_hash!
|
|
expect(f.service.serialize).to eq(serialized_hash)
|
|
Formula.generated_hash!
|
|
end
|
|
end
|
|
|
|
describe ".deserialize" do
|
|
let(:serialized_hash) do
|
|
{
|
|
"name" => {
|
|
"linux" => "custom.systemd.name",
|
|
"macos" => "custom.launchd.name",
|
|
},
|
|
"environment_variables" => {
|
|
"PATH" => "$HOMEBREW_PREFIX/bin:$HOMEBREW_PREFIX/sbin:/usr/bin:/bin:/usr/sbin:/sbin",
|
|
},
|
|
"run" => ["$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd", "test"],
|
|
"run_type" => "immediate",
|
|
"working_dir" => HOMEBREW_HOME_PLACEHOLDER,
|
|
"keep_alive" => { "successful_exit" => false },
|
|
}
|
|
end
|
|
|
|
let(:deserialized_hash) do
|
|
{
|
|
name: {
|
|
linux: "custom.systemd.name",
|
|
macos: "custom.launchd.name",
|
|
},
|
|
environment_variables: {
|
|
PATH: "#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin",
|
|
},
|
|
run: ["#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd", "test"],
|
|
run_type: :immediate,
|
|
working_dir: Dir.home,
|
|
keep_alive: { successful_exit: false },
|
|
}
|
|
end
|
|
|
|
it "replaces placeholders with local paths" do
|
|
expect(described_class.deserialize(serialized_hash)).to eq(deserialized_hash)
|
|
end
|
|
|
|
describe "run command" do
|
|
it "handles String argument correctly" do
|
|
expect(described_class.deserialize({
|
|
"run" => "$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd",
|
|
})).to eq({
|
|
run: "#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd",
|
|
})
|
|
end
|
|
|
|
it "handles Array argument correctly" do
|
|
expect(described_class.deserialize({
|
|
"run" => ["$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd", "--option"],
|
|
})).to eq({
|
|
run: ["#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd", "--option"],
|
|
})
|
|
end
|
|
|
|
it "handles Hash argument correctly" do
|
|
expect(described_class.deserialize({
|
|
"run" => {
|
|
"linux" => "$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd",
|
|
"macos" => ["$HOMEBREW_PREFIX/opt/formula_name/bin/beanstalkd", "--option"],
|
|
},
|
|
})).to eq({
|
|
run: {
|
|
linux: "#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd",
|
|
macos: ["#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd", "--option"],
|
|
},
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|