322 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
# frozen_string_literal: true
 | 
						|
 | 
						|
require "services/cli"
 | 
						|
require "services/system"
 | 
						|
require "services/formula_wrapper"
 | 
						|
 | 
						|
RSpec.describe Homebrew::Services::Cli do
 | 
						|
  subject(:services_cli) { described_class }
 | 
						|
 | 
						|
  let(:service_string) { "service" }
 | 
						|
 | 
						|
  describe "#bin" do
 | 
						|
    it "outputs command name" do
 | 
						|
      expect(services_cli.bin).to eq("brew services")
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#running" do
 | 
						|
    it "macOS - returns the currently running services" do
 | 
						|
      allow(Homebrew::Services::System).to receive_messages(launchctl?: true, systemctl?: false)
 | 
						|
      allow(Utils).to receive(:popen_read).and_return <<~EOS
 | 
						|
        77513   50  homebrew.mxcl.php
 | 
						|
        495     0   homebrew.mxcl.node_exporter
 | 
						|
        1234    34  homebrew.mxcl.postgresql@14
 | 
						|
      EOS
 | 
						|
      expect(services_cli.running).to eq([
 | 
						|
        "homebrew.mxcl.php",
 | 
						|
        "homebrew.mxcl.node_exporter",
 | 
						|
        "homebrew.mxcl.postgresql@14",
 | 
						|
      ])
 | 
						|
    end
 | 
						|
 | 
						|
    it "systemD - returns the currently running services" do
 | 
						|
      allow(Homebrew::Services::System).to receive(:launchctl?).and_return(false)
 | 
						|
      allow(Homebrew::Services::System::Systemctl).to receive(:popen_read).and_return <<~EOS
 | 
						|
        homebrew.php.service     loaded active running Homebrew PHP service
 | 
						|
        systemd-udevd.service    loaded active running Rule-based Manager for Device Events and Files
 | 
						|
        udisks2.service          loaded active running Disk Manager
 | 
						|
        user@1000.service        loaded active running User Manager for UID 1000
 | 
						|
      EOS
 | 
						|
      expect(services_cli.running).to eq(["homebrew.php.service"])
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#check!" do
 | 
						|
    it "checks the input does not exist" do
 | 
						|
      expect do
 | 
						|
        services_cli.check!([])
 | 
						|
      end.to raise_error(UsageError,
 | 
						|
                         "Invalid usage: Formula(e) missing, please provide a formula name or use `--all`.")
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks the input exists" do
 | 
						|
      expect do
 | 
						|
        services_cli.check!("hello")
 | 
						|
      end.not_to raise_error(UsageError,
 | 
						|
                             "Invalid usage: Formula(e) missing, please provide a formula name or use `--all`.")
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#kill_orphaned_services" do
 | 
						|
    it "skips unmanaged services" do
 | 
						|
      allow(services_cli).to receive(:running).and_return(["example_service"])
 | 
						|
      expect do
 | 
						|
        services_cli.kill_orphaned_services
 | 
						|
      end.to output("Warning: Service example_service not managed by `brew services` => skipping\n").to_stderr
 | 
						|
    end
 | 
						|
 | 
						|
    it "tries but is unable to kill a non existing service" do
 | 
						|
      service = instance_double(
 | 
						|
        service_string,
 | 
						|
        name:        "example_service",
 | 
						|
        pid?:        true,
 | 
						|
        dest:        Pathname("this_path_does_not_exist"),
 | 
						|
        keep_alive?: false,
 | 
						|
      )
 | 
						|
      allow(service).to receive(:service_name)
 | 
						|
      allow(service).to receive(:reset_cache!)
 | 
						|
      allow(Homebrew::Services::FormulaWrapper).to receive(:from).and_return(service)
 | 
						|
      allow(services_cli).to receive(:running).and_return(["example_service"])
 | 
						|
      expect do
 | 
						|
        services_cli.kill_orphaned_services
 | 
						|
      end.to output("Killing `example_service`... (might take a while)\n").to_stdout
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#run" do
 | 
						|
    it "checks missing file causes error" do
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:root?)
 | 
						|
      expect do
 | 
						|
        services_cli.start(["service_name"], "/non/existent/path")
 | 
						|
      end.to raise_error(UsageError, "Invalid usage: Provided service file does not exist.")
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks empty targets cause no error" do
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:root?)
 | 
						|
      services_cli.run([])
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks if target service is already running and suggests restart instead" do
 | 
						|
      expected_output = "Service `example_service` already running, " \
 | 
						|
                        "use `brew services restart example_service` to restart.\n"
 | 
						|
      service = instance_double(service_string, name: "example_service", pid?: true)
 | 
						|
      expect do
 | 
						|
        services_cli.run([service])
 | 
						|
      end.to output(expected_output).to_stdout
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#start" do
 | 
						|
    it "checks missing file causes error" do
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:root?)
 | 
						|
      expect do
 | 
						|
        services_cli.start(["service_name"], "/hfdkjshksdjhfkjsdhf/fdsjghsdkjhb")
 | 
						|
      end.to raise_error(UsageError, "Invalid usage: Provided service file does not exist.")
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks empty targets cause no error" do
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:root?)
 | 
						|
      services_cli.start([])
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks if target service has already been started and suggests restart instead" do
 | 
						|
      expected_output = "Service `example_service` already started, " \
 | 
						|
                        "use `brew services restart example_service` to restart.\n"
 | 
						|
      service = instance_double(service_string, name: "example_service", pid?: true)
 | 
						|
      expect do
 | 
						|
        services_cli.start([service])
 | 
						|
      end.to output(expected_output).to_stdout
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#stop" do
 | 
						|
    it "checks empty targets cause no error" do
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:root?)
 | 
						|
      services_cli.stop([])
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#kill" do
 | 
						|
    it "checks empty targets cause no error" do
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:root?)
 | 
						|
      services_cli.kill([])
 | 
						|
    end
 | 
						|
 | 
						|
    it "prints a message if service is not running" do
 | 
						|
      expected_output = "Service `example_service` is not started.\n"
 | 
						|
      service = instance_double(service_string, name: "example_service", pid?: false)
 | 
						|
      expect do
 | 
						|
        services_cli.kill([service])
 | 
						|
      end.to output(expected_output).to_stdout
 | 
						|
    end
 | 
						|
 | 
						|
    it "prints a message if service is set to keep alive" do
 | 
						|
      expected_output = "Service `example_service` is set to automatically restart and can't be killed.\n"
 | 
						|
      service = instance_double(service_string, name: "example_service", pid?: true, keep_alive?: true)
 | 
						|
      expect do
 | 
						|
        services_cli.kill([service])
 | 
						|
      end.to output(expected_output).to_stdout
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#install_service_file" do
 | 
						|
    it "checks service is installed" do
 | 
						|
      service = instance_double(Homebrew::Services::FormulaWrapper, name: "name", installed?: false)
 | 
						|
      expect do
 | 
						|
        services_cli.install_service_file(service, nil)
 | 
						|
      end.to raise_error(UsageError, "Invalid usage: Formula `name` is not installed.")
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks service file exists" do
 | 
						|
      service = instance_double(
 | 
						|
        Homebrew::Services::FormulaWrapper,
 | 
						|
        name:         "name",
 | 
						|
        installed?:   true,
 | 
						|
        service_file: instance_double(Pathname, exist?: false),
 | 
						|
      )
 | 
						|
      expect do
 | 
						|
        services_cli.install_service_file(service, nil)
 | 
						|
      end.to raise_error(
 | 
						|
        UsageError,
 | 
						|
        "Invalid usage: Formula `name` has not implemented #plist, #service or provided a locatable service file.",
 | 
						|
      )
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#systemd_load", :needs_linux do
 | 
						|
    it "checks non-enabling run" do
 | 
						|
      expect(Homebrew::Services::System::Systemctl).to receive(:run).once.and_return(true)
 | 
						|
      services_cli.systemd_load(
 | 
						|
        instance_double(Homebrew::Services::FormulaWrapper, service_name: "name"),
 | 
						|
        enable: false,
 | 
						|
      )
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks enabling run" do
 | 
						|
      expect(Homebrew::Services::System::Systemctl).to receive(:run).twice.and_return(true)
 | 
						|
      services_cli.systemd_load(
 | 
						|
        instance_double(Homebrew::Services::FormulaWrapper, service_name: "name"),
 | 
						|
        enable: true,
 | 
						|
      )
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#launchctl_load", :needs_macos do
 | 
						|
    it "checks non-enabling run" do
 | 
						|
      allow(Homebrew::Services::System).to receive(:launchctl).and_return(Pathname.new("/bin/launchctl"))
 | 
						|
      expect(Homebrew::Services::System).to receive(:domain_target).once.and_return("target")
 | 
						|
      expect(described_class).to receive(:safe_system).once.and_return(true)
 | 
						|
      services_cli.launchctl_load(instance_double(Homebrew::Services::FormulaWrapper), file: "a", enable: false)
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks enabling run" do
 | 
						|
      allow(Homebrew::Services::System).to receive(:launchctl).and_return(Pathname.new("/bin/launchctl"))
 | 
						|
      expect(Homebrew::Services::System).to receive(:domain_target).twice.and_return("target")
 | 
						|
      expect(described_class).to receive(:safe_system).twice.and_return(true)
 | 
						|
      services_cli.launchctl_load(instance_double(Homebrew::Services::FormulaWrapper, service_name: "name"),
 | 
						|
                                  file:   "a",
 | 
						|
                                  enable: true)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  describe "#service_load" do
 | 
						|
    it "checks non-root for login" do
 | 
						|
      expect(Homebrew::Services::System).to receive(:launchctl?).once.and_return(false)
 | 
						|
      expect(Homebrew::Services::System).to receive(:systemctl?).once.and_return(false)
 | 
						|
      expect(Homebrew::Services::System).to receive(:root?).once.and_return(true)
 | 
						|
 | 
						|
      expect do
 | 
						|
        services_cli.service_load(
 | 
						|
          instance_double(
 | 
						|
            Homebrew::Services::FormulaWrapper,
 | 
						|
            name:             "name",
 | 
						|
            service_name:     "service.name",
 | 
						|
            service_startup?: false,
 | 
						|
          ),
 | 
						|
          nil,
 | 
						|
          enable: false,
 | 
						|
        )
 | 
						|
      end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
 | 
						|
    end
 | 
						|
 | 
						|
    it "checks root for startup" do
 | 
						|
      expect(Homebrew::Services::System).to receive(:launchctl?).once.and_return(false)
 | 
						|
      expect(Homebrew::Services::System).to receive(:systemctl?).once.and_return(false)
 | 
						|
      expect(Homebrew::Services::System).to receive(:root?).twice.and_return(false)
 | 
						|
      expect do
 | 
						|
        services_cli.service_load(
 | 
						|
          instance_double(
 | 
						|
            Homebrew::Services::FormulaWrapper,
 | 
						|
            name:             "name",
 | 
						|
            service_name:     "service.name",
 | 
						|
            service_startup?: true,
 | 
						|
          ),
 | 
						|
          nil,
 | 
						|
          enable: false,
 | 
						|
        )
 | 
						|
      end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
 | 
						|
    end
 | 
						|
 | 
						|
    it "triggers launchctl" do
 | 
						|
      expect(Homebrew::Services::System).to receive(:launchctl?).once.and_return(true)
 | 
						|
      expect(Homebrew::Services::System).not_to receive(:systemctl?)
 | 
						|
      expect(Homebrew::Services::System).to receive(:root?).twice.and_return(false)
 | 
						|
      expect(described_class).to receive(:launchctl_load).once.and_return(true)
 | 
						|
      expect do
 | 
						|
        services_cli.service_load(
 | 
						|
          instance_double(
 | 
						|
            Homebrew::Services::FormulaWrapper,
 | 
						|
            name:             "name",
 | 
						|
            service_name:     "service.name",
 | 
						|
            service_startup?: false,
 | 
						|
            service_file:     instance_double(Pathname, exist?: false),
 | 
						|
          ),
 | 
						|
          nil,
 | 
						|
          enable: false,
 | 
						|
        )
 | 
						|
      end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
 | 
						|
    end
 | 
						|
 | 
						|
    it "triggers systemctl" do
 | 
						|
      expect(Homebrew::Services::System).to receive(:launchctl?).once.and_return(false)
 | 
						|
      expect(Homebrew::Services::System).to receive(:systemctl?).once.and_return(true)
 | 
						|
      expect(Homebrew::Services::System).to receive(:root?).twice.and_return(false)
 | 
						|
      expect(Homebrew::Services::System::Systemctl).to receive(:run).once.and_return(true)
 | 
						|
      expect do
 | 
						|
        services_cli.service_load(
 | 
						|
          instance_double(
 | 
						|
            Homebrew::Services::FormulaWrapper,
 | 
						|
            name:             "name",
 | 
						|
            service_name:     "service.name",
 | 
						|
            service_startup?: false,
 | 
						|
            dest:             instance_double(Pathname, exist?: true),
 | 
						|
          ),
 | 
						|
          nil,
 | 
						|
          enable: false,
 | 
						|
        )
 | 
						|
      end.to output("==> Successfully ran `name` (label: service.name)\n").to_stdout
 | 
						|
    end
 | 
						|
 | 
						|
    it "represents correct action" do
 | 
						|
      expect(Homebrew::Services::System).to receive(:launchctl?).once.and_return(false)
 | 
						|
      expect(Homebrew::Services::System).to receive(:systemctl?).once.and_return(true)
 | 
						|
      expect(Homebrew::Services::System).to receive(:root?).twice.and_return(false)
 | 
						|
      expect(Homebrew::Services::System::Systemctl).to receive(:run).twice.and_return(true)
 | 
						|
      expect do
 | 
						|
        services_cli.service_load(
 | 
						|
          instance_double(
 | 
						|
            Homebrew::Services::FormulaWrapper,
 | 
						|
            name:             "name",
 | 
						|
            service_name:     "service.name",
 | 
						|
            service_startup?: false,
 | 
						|
            dest:             instance_double(Pathname, exist?: true),
 | 
						|
          ),
 | 
						|
          nil,
 | 
						|
          enable: true,
 | 
						|
        )
 | 
						|
      end.to output("==> Successfully started `name` (label: service.name)\n").to_stdout
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 |