chromium/chrome/test/base/chromeos/crosier/upstart.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_TEST_BASE_CHROMEOS_CROSIER_UPSTART_H_
#define CHROME_TEST_BASE_CHROMEOS_CROSIER_UPSTART_H_

#include <string>
#include <vector>

#include "base/time/time.h"

// This file is a wrapper around the "initctl" command-line program that is used
// to control the system "upstart" daemon manager.

namespace upstart {

enum class Goal {
  kInvalid,  // Goal could not be queried or is unavailable.
  kStart,
  kStop
};

Goal GoalFromString(std::string_view s);
std::string_view GoalToString(Goal g);

enum class State {
  kInvalid,  // State could not be queried or is unavailable.
  kWaiting,
  kStarting,
  kSecurity,
  kTmpfiles,
  kPreStart,
  kSpawned,
  kPostStart,
  kRunning,
  kPreStop,
  kStopping,
  kKilled,
  kPostStop
};

State StateFromString(std::string_view s);
std::string_view StateFromString(State s);

// Dumps the current job list to stdout. Returns true on success.
bool DumpJobs();

struct JobStatus {
  bool is_valid = false;  // Set when the status was successfully queried.
  Goal goal = Goal::kInvalid;
  State state = State::kInvalid;
  int pid = 0;
};

// The extra_args is passed to the job as extra parameters, see StartJob().
JobStatus GetJobStatus(const std::string& job,
                       const std::vector<std::string>& extra_args = {});

// Returns true if the supplied job exists (i.e. it has a config file known by
// Upstart).
bool JobExists(const std::string& job);

// Starts job. If it is already running, this returns an error.
//
// The extra_args is passed to the job as extra parameters. For example,
// multiple-instance jobs can use it to specify an instance. The format of each
// extra_args string is "<key>=<value>" so:
//   StartJob("cryptohomed, {"LOG_LEVEL=-2"});
bool StartJob(const std::string& job,
              const std::vector<std::string>& extra_args = {});

// Restarts the job (single-instance) or the specified instance of the job
// (multiple-instance). If the job (instance) is currently stopped, it will be
// started. Note that the job is reloaded if it is already running; this differs
// from the "initctl restart" behavior as described in Section 10.1.2,
// "restart", in the Upstart Cookbook.
//
// The extra_args is passed to the job as extra parameters, see StartJob().
bool RestartJob(const std::string& job,
                const std::vector<std::string>& extra_args = {});

// StopJob stops job or the specified job instance. If it is not currently
// running, this is a no-op.
//
// The extra_args is passed to the job as extra parameters, see StartJob().
bool StopJob(const std::string& job,
             const std::vector<std::string>& extra_args = {});

// Starts the job if it isn't currently running. If it is already running, this
// is a no-op.
//
// The extra_args is passed to the job as extra parameters, see StartJob().
bool EnsureJobRunning(const std::string& job,
                      const std::vector<std::string>& extra_args = {});

enum class WrongGoalPolicy {
  // Indicates that it's acceptable for the job to initially have a goal that
  // doesn't match the requested one. WaitForJobStatus will continue waiting for
  // the requested goal.
  kTolerate,

  // RejectWrongGoal indicates that an error should be returned immediately if
  // the job doesn't have the requested goal.
  kReject
};

// Waits for job to have the status described by goal/state. The |policy|
// controls the function's behavior if the job's goal doesn't match the
// requested one. Returns true if the status was matched, false if it went to an
// invalid state or timed out.
//
// Automatically times out according to the process' TestTimeouts.
//
// The extra_args is passed to the job as extra parameters, see StartJob().
bool WaitForJobStatus(const std::string& job,
                      Goal goal,
                      State state,
                      WrongGoalPolicy policy,
                      const std::vector<std::string>& extra_args = {});

namespace internal {

// Parses the result of the "initctl status" for the expected job name. Exposed
// for testing.
JobStatus ParseStatus(std::string_view job_name, std::string_view s);

// Like WaitForJobStatus() but exposes the timeout for internal testing. Normal
// tests should always use WaitForJobStatus() which will use the default testing
// timeout.
bool WaitForJobStatusWithTimeout(
    const std::string& job,
    Goal goal,
    State state,
    WrongGoalPolicy policy,
    base::TimeDelta timeout,
    const std::vector<std::string>& extra_args = {});

}  // namespace internal

}  // namespace upstart

#endif  // CHROME_TEST_BASE_CHROMEOS_CROSIER_UPSTART_H_