# typed: false # frozen_string_literal: true require "formula" require "service" describe Homebrew::Service do let(:klass) do Class.new(Formula) do url "https://brew.sh/test-1.0.tbz" end end let(:name) { "formula_name" } let(:path) { Formulary.core_path(name) } let(:spec) { :stable } let(:f) { klass.new(name, path, spec) } describe "#std_service_path_env" do it "returns valid std_service_path_env" do f.class.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 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.class.service do run opt_bin/"beanstalkd" process_type :cow end expect { f.service.manual_command }.to raise_error TypeError, "Service#process_type allows: 'background'/'standard'/'interactive'/'adaptive'" end end describe "#run_type" do it "throws for unexpected type" do f.class.service do run opt_bin/"beanstalkd" run_type :cow end expect { f.service.manual_command }.to raise_error TypeError, "Service#run_type allows: 'immediate'/'interval'/'cron'" end end describe "#manual_command" do it "returns valid manual_command" do f.class.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 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.class.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 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.class.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" root_dir var working_dir var keep_alive true process_type :interactive restart_delay 30 interval 5 macos_legacy_timers true end plist = f.service.to_plist plist_expect = <<~EOS \tEnvironmentVariables \t \t\tETC_DIR \t\t#{HOMEBREW_PREFIX}/etc/beanstalkd \t\tFOO \t\tBAR \t\tPATH \t\t#{HOMEBREW_PREFIX}/bin:#{HOMEBREW_PREFIX}/sbin:/usr/bin:/bin:/usr/sbin:/sbin \t \tKeepAlive \t \tLabel \thomebrew.mxcl.formula_name \tLegacyTimers \t \tProcessType \tInteractive \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd \t\ttest \t \tRootDirectory \t#{HOMEBREW_PREFIX}/var \tRunAtLoad \t \tStandardErrorPath \t#{HOMEBREW_PREFIX}/var/log/beanstalkd.error.log \tStandardInPath \t#{HOMEBREW_PREFIX}/var/in/beanstalkd \tStandardOutPath \t#{HOMEBREW_PREFIX}/var/log/beanstalkd.log \tTimeOut \t30 \tWorkingDirectory \t#{HOMEBREW_PREFIX}/var EOS expect(plist).to eq(plist_expect) end it "returns valid partial plist" do f.class.service do run opt_bin/"beanstalkd" run_type :immediate end plist = f.service.to_plist plist_expect = <<~EOS \tLabel \thomebrew.mxcl.formula_name \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd \t \tRunAtLoad \t EOS expect(plist).to eq(plist_expect) end it "returns valid interval plist" do f.class.service do run opt_bin/"beanstalkd" run_type :interval interval 5 end plist = f.service.to_plist plist_expect = <<~EOS \tLabel \thomebrew.mxcl.formula_name \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd \t \tRunAtLoad \t \tStartInterval \t5 EOS expect(plist).to eq(plist_expect) end it "returns valid cron plist" do f.class.service do run opt_bin/"beanstalkd" run_type :cron cron "@daily" end plist = f.service.to_plist plist_expect = <<~EOS \tLabel \thomebrew.mxcl.formula_name \tProgramArguments \t \t\t#{HOMEBREW_PREFIX}/opt/formula_name/bin/beanstalkd \t \tRunAtLoad \t \tStartCalendarInterval \t \t\tHour \t\t0 \t\tMinute \t\t0 \t EOS expect(plist).to eq(plist_expect) end end describe "#to_systemd_unit" do it "returns valid unit" do f.class.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" root_dir var working_dir var keep_alive true process_type :interactive restart_delay 30 macos_legacy_timers true 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=multi-user.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 unit" do f.class.service do run opt_bin/"beanstalkd" run_type :immediate end unit = f.service.to_systemd_unit unit_expect = <<~EOS [Unit] Description=Homebrew generated unit for formula_name [Install] WantedBy=multi-user.target [Service] Type=simple ExecStart=#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd EOS expect(unit).to eq(unit_expect) end end describe "#to_systemd_timer" do it "returns valid timer" do f.class.service do run [opt_bin/"beanstalkd", "test"] run_type :interval interval 5 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.class.service do run opt_bin/"beanstalkd" run_type :immediate 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.class.service do run opt_bin/"beanstalkd" run_type :cron cron "1 2 3 4" end expect { f.service.to_systemd_timer }.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.class.service do run opt_bin/"beanstalkd" run_type :cron cron cron.to_s 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.class.service do run [opt_bin/"beanstalkd", "test"] run_type :immediate end expect(f.service.timed?).to eq(false) end it "returns true for interval" do f.class.service do run [opt_bin/"beanstalkd", "test"] run_type :interval end expect(f.service.timed?).to eq(true) end end describe "#command" do it "returns @run data" do f.class.service do run [opt_bin/"beanstalkd", "test"] run_type :immediate end command = f.service.command expect(command).to eq(["#{HOMEBREW_PREFIX}/opt/#{name}/bin/beanstalkd", "test"]) end end end