func TestReloadOrRestartUnit(t *testing.T) {
	target := "reload.service"
	conn := setupConn(t)
	defer conn.Close()
	setupUnit(target, conn, t)
	linkUnit(target, conn, t)
	reschan := make(chan string)
	_, err := conn.StartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job := <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	units, err := conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit := getUnitStatus(units, target)
	if unit == nil {
		t.Fatalf("Test unit not found in list")
	} else if unit.ActiveState != "active" {
		t.Fatalf("Test unit not active")
	}
	reschan = make(chan string)
	_, err = conn.ReloadOrRestartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job = <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	_, err = conn.StopUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	<-reschan
	units, err = conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit = getUnitStatus(units, target)
	if unit != nil && unit.ActiveState == "active" {
		t.Fatalf("Test unit still active, should be inactive.")
	}
	reschan = make(chan string)
	_, err = conn.ReloadOrTryRestartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job = <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
}
Ensure that basic unit reload-or-restarting works.
package dbus
import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"reflect"
	"syscall"
	"testing"
	"time"
	"github.com/godbus/dbus"
)
type TrUnitProp struct {
	name  string
	props []Property
}
func setupConn(t *testing.T) *Conn {
	conn, err := New()
	if err != nil {
		t.Fatal(err)
	}
	return conn
}
func findFixture(target string, t *testing.T) string {
	abs, err := filepath.Abs("../fixtures/" + target)
	if err != nil {
		t.Fatal(err)
	}
	return abs
}
func setupUnit(target string, conn *Conn, t *testing.T) {
	conn.StopUnit(target, "replace", nil)
	targetRun := filepath.Join("/run/systemd/system/", target)
	os.Remove(targetRun)
}
func linkUnit(target string, conn *Conn, t *testing.T) {
	abs := findFixture(target, t)
	fixture := []string{abs}
	changes, err := conn.LinkUnitFiles(fixture, true, true)
	if err != nil {
		t.Fatal(err)
	}
	if len(changes) < 1 {
		t.Fatalf("Expected one change, got %v", changes)
	}
	runPath := filepath.Join("/run/systemd/system/", target)
	if changes[0].Filename != runPath {
		t.Fatal("Unexpected target filename")
	}
}
func getUnitStatus(units []UnitStatus, name string) *UnitStatus {
	for _, u := range units {
		if u.Name == name {
			return &u
		}
	}
	return nil
}
func getUnitStatusSingle(conn *Conn, name string) *UnitStatus {
	units, err := conn.ListUnits()
	if err != nil {
		return nil
	}
	return getUnitStatus(units, name)
}
func getUnitFile(units []UnitFile, name string) *UnitFile {
	for _, u := range units {
		if path.Base(u.Path) == name {
			return &u
		}
	}
	return nil
}
func runStartTrUnit(t *testing.T, conn *Conn, trTarget TrUnitProp) error {
	reschan := make(chan string)
	_, err := conn.StartTransientUnit(trTarget.name, "replace", trTarget.props, reschan)
	if err != nil {
		return err
	}
	job := <-reschan
	if job != "done" {
		return fmt.Errorf("Job is not done: %s", job)
	}
	return nil
}
func runStopUnit(t *testing.T, conn *Conn, trTarget TrUnitProp) error {
	reschan := make(chan string)
	_, err := conn.StopUnit(trTarget.name, "replace", reschan)
	if err != nil {
		return err
	}
	<-reschan
	return nil
}
func TestStartStopUnit(t *testing.T) {
	target := "start-stop.service"
	conn := setupConn(t)
	defer conn.Close()
	setupUnit(target, conn, t)
	linkUnit(target, conn, t)
	reschan := make(chan string)
	_, err := conn.StartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job := <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	units, err := conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit := getUnitStatus(units, target)
	if unit == nil {
		t.Fatalf("Test unit not found in list")
	} else if unit.ActiveState != "active" {
		t.Fatalf("Test unit not active")
	}
	_, err = conn.StopUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	<-reschan
	units, err = conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit = getUnitStatus(units, target)
	if unit != nil {
		t.Fatalf("Test unit found in list, should be stopped")
	}
}
func TestRestartUnit(t *testing.T) {
	target := "start-stop.service"
	conn := setupConn(t)
	defer conn.Close()
	setupUnit(target, conn, t)
	linkUnit(target, conn, t)
	reschan := make(chan string)
	_, err := conn.StartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job := <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	units, err := conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit := getUnitStatus(units, target)
	if unit == nil {
		t.Fatalf("Test unit not found in list")
	} else if unit.ActiveState != "active" {
		t.Fatalf("Test unit not active")
	}
	reschan = make(chan string)
	_, err = conn.RestartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job = <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	_, err = conn.StopUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	<-reschan
	units, err = conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit = getUnitStatus(units, target)
	if unit != nil {
		t.Fatalf("Test unit found in list, should be stopped")
	}
	reschan = make(chan string)
	_, err = conn.TryRestartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	<-reschan
	units, err = conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit = getUnitStatus(units, target)
	if unit != nil {
		t.Fatalf("Test unit found in list, should be stopped")
	}
}
func TestReloadUnit(t *testing.T) {
	target := "reload.service"
	conn := setupConn(t)
	defer conn.Close()
	err := conn.Subscribe()
	if err != nil {
		t.Fatal(err)
	}
	subSet := conn.NewSubscriptionSet()
	evChan, errChan := subSet.Subscribe()
	subSet.Add(target)
	setupUnit(target, conn, t)
	linkUnit(target, conn, t)
	reschan := make(chan string)
	_, err = conn.StartUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job := <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	units, err := conn.ListUnits()
	if err != nil {
		t.Fatal(err)
	}
	unit := getUnitStatus(units, target)
	if unit == nil {
		t.Fatalf("Test unit not found in list")
	} else if unit.ActiveState != "active" {
		t.Fatalf("Test unit not active")
	}
	reschan = make(chan string)
	_, err = conn.ReloadUnit(target, "replace", reschan)
	if err != nil {
		t.Fatal(err)
	}
	job = <-reschan
	if job != "done" {
		t.Fatal("Job is not done:", job)
	}
	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(3 * time.Second)
		close(timeout)
	}()
waitevent:
	for {
		select {
		case changes := <-evChan:
			tch, ok := changes[target]
			if !ok {
				continue waitevent
			}
			if tch != nil && tch.Name == target && tch.ActiveState == "active" {
				break waitevent
			}
		case err = <-errChan:
			t.Fatal(err)
		case <-timeout:
			t.Fatal("Reached timeout")
		}
	}
}