Skip to content

Commit f193a6f

Browse files
committed
Merge pull request #150 from endocode/kayrus/ListUnitsFiltered
dbus: add support for new ListUnits* methods
2 parents 4484981 + c498a32 commit f193a6f

File tree

3 files changed

+227
-39
lines changed

3 files changed

+227
-39
lines changed

dbus/methods.go

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,11 @@ type UnitStatus struct {
239239
JobPath dbus.ObjectPath // The job object path
240240
}
241241

242-
// ListUnits returns an array with all currently loaded units. Note that
243-
// units may be known by multiple names at the same time, and hence there might
244-
// be more unit names loaded than actual units behind them.
245-
func (c *Conn) ListUnits() ([]UnitStatus, error) {
242+
type storeFunc func(retvalues ...interface{}) error
243+
244+
func (c *Conn) listUnitsInternal(f storeFunc) ([]UnitStatus, error) {
246245
result := make([][]interface{}, 0)
247-
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store(&result)
246+
err := f(&result)
248247
if err != nil {
249248
return nil, err
250249
}
@@ -268,15 +267,43 @@ func (c *Conn) ListUnits() ([]UnitStatus, error) {
268267
return status, nil
269268
}
270269

270+
// ListUnits returns an array with all currently loaded units. Note that
271+
// units may be known by multiple names at the same time, and hence there might
272+
// be more unit names loaded than actual units behind them.
273+
func (c *Conn) ListUnits() ([]UnitStatus, error) {
274+
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnits", 0).Store)
275+
}
276+
277+
// ListUnitsFiltered returns an array with units filtered by state.
278+
// It takes a list of units' statuses to filter.
279+
func (c *Conn) ListUnitsFiltered(states []string) ([]UnitStatus, error) {
280+
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsFiltered", 0, states).Store)
281+
}
282+
283+
// ListUnitsByPatterns returns an array with units.
284+
// It takes a list of units' statuses and names to filter.
285+
// Note that units may be known by multiple names at the same time,
286+
// and hence there might be more unit names loaded than actual units behind them.
287+
func (c *Conn) ListUnitsByPatterns(states []string, patterns []string) ([]UnitStatus, error) {
288+
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByPatterns", 0, states, patterns).Store)
289+
}
290+
291+
// ListUnitsByNames returns an array with units. It takes a list of units'
292+
// names and returns an UnitStatus array. Comparing to ListUnitsByPatterns
293+
// method, this method returns statuses even for inactive or non-existing
294+
// units. Input array should contain exact unit names, but not patterns.
295+
func (c *Conn) ListUnitsByNames(units []string) ([]UnitStatus, error) {
296+
return c.listUnitsInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitsByNames", 0, units).Store)
297+
}
298+
271299
type UnitFile struct {
272300
Path string
273301
Type string
274302
}
275303

276-
// ListUnitFiles returns an array of all available units on disk.
277-
func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
304+
func (c *Conn) listUnitFilesInternal(f storeFunc) ([]UnitFile, error) {
278305
result := make([][]interface{}, 0)
279-
err := c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store(&result)
306+
err := f(&result)
280307
if err != nil {
281308
return nil, err
282309
}
@@ -300,6 +327,16 @@ func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
300327
return files, nil
301328
}
302329

330+
// ListUnitFiles returns an array of all available units on disk.
331+
func (c *Conn) ListUnitFiles() ([]UnitFile, error) {
332+
return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFiles", 0).Store)
333+
}
334+
335+
// ListUnitFilesByPatterns returns an array of all available units on disk matched the patterns.
336+
func (c *Conn) ListUnitFilesByPatterns(states []string, patterns []string) ([]UnitFile, error) {
337+
return c.listUnitFilesInternal(c.sysobj.Call("org.freedesktop.systemd1.Manager.ListUnitFilesByPatterns", 0, states, patterns).Store)
338+
}
339+
303340
type LinkUnitFileChange EnableUnitFileChange
304341

305342
// LinkUnitFiles() links unit files (that are located outside of the

dbus/methods_test.go

Lines changed: 181 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"fmt"
1919
"math/rand"
2020
"os"
21+
"path"
2122
"path/filepath"
2223
"reflect"
2324
"testing"
@@ -70,6 +71,24 @@ func linkUnit(target string, conn *Conn, t *testing.T) {
7071
}
7172
}
7273

74+
func getUnitStatus(units []UnitStatus, name string) *UnitStatus {
75+
for _, u := range units {
76+
if u.Name == name {
77+
return &u
78+
}
79+
}
80+
return nil
81+
}
82+
83+
func getUnitFile(units []UnitFile, name string) *UnitFile {
84+
for _, u := range units {
85+
if path.Base(u.Path) == name {
86+
return &u
87+
}
88+
}
89+
return nil
90+
}
91+
7392
// Ensure that basic unit starting and stopping works.
7493
func TestStartStopUnit(t *testing.T) {
7594
target := "start-stop.service"
@@ -92,18 +111,11 @@ func TestStartStopUnit(t *testing.T) {
92111

93112
units, err := conn.ListUnits()
94113

95-
var unit *UnitStatus
96-
for _, u := range units {
97-
if u.Name == target {
98-
unit = &u
99-
}
100-
}
114+
unit := getUnitStatus(units, target)
101115

102116
if unit == nil {
103117
t.Fatalf("Test unit not found in list")
104-
}
105-
106-
if unit.ActiveState != "active" {
118+
} else if unit.ActiveState != "active" {
107119
t.Fatalf("Test unit not active")
108120
}
109121

@@ -118,18 +130,169 @@ func TestStartStopUnit(t *testing.T) {
118130

119131
units, err = conn.ListUnits()
120132

121-
unit = nil
122-
for _, u := range units {
123-
if u.Name == target {
124-
unit = &u
125-
}
126-
}
133+
unit = getUnitStatus(units, target)
127134

128135
if unit != nil {
129136
t.Fatalf("Test unit found in list, should be stopped")
130137
}
131138
}
132139

140+
// Ensure that ListUnitsByNames works.
141+
func TestListUnitsByNames(t *testing.T) {
142+
target1 := "systemd-journald.service"
143+
target2 := "unexisting.service"
144+
145+
conn := setupConn(t)
146+
147+
units, err := conn.ListUnitsByNames([]string{target1, target2})
148+
149+
if err != nil {
150+
t.Skip(err)
151+
}
152+
153+
unit := getUnitStatus(units, target1)
154+
155+
if unit == nil {
156+
t.Fatalf("%s unit not found in list", target1)
157+
} else if unit.ActiveState != "active" {
158+
t.Fatalf("%s unit should be active but it is %s", target1, unit.ActiveState)
159+
}
160+
161+
unit = getUnitStatus(units, target2)
162+
163+
if unit == nil {
164+
t.Fatalf("Unexisting test unit not found in list")
165+
} else if unit.ActiveState != "inactive" {
166+
t.Fatalf("Test unit should be inactive")
167+
}
168+
}
169+
170+
// Ensure that ListUnitsByPatterns works.
171+
func TestListUnitsByPatterns(t *testing.T) {
172+
target1 := "systemd-journald.service"
173+
target2 := "unexisting.service"
174+
175+
conn := setupConn(t)
176+
177+
units, err := conn.ListUnitsByPatterns([]string{}, []string{"systemd-journald*", target2})
178+
179+
if err != nil {
180+
t.Skip(err)
181+
}
182+
183+
unit := getUnitStatus(units, target1)
184+
185+
if unit == nil {
186+
t.Fatalf("%s unit not found in list", target1)
187+
} else if unit.ActiveState != "active" {
188+
t.Fatalf("Test unit should be active")
189+
}
190+
191+
unit = getUnitStatus(units, target2)
192+
193+
if unit != nil {
194+
t.Fatalf("Unexisting test unit found in list")
195+
}
196+
}
197+
198+
// Ensure that ListUnitsFiltered works.
199+
func TestListUnitsFiltered(t *testing.T) {
200+
target := "systemd-journald.service"
201+
202+
conn := setupConn(t)
203+
204+
units, err := conn.ListUnitsFiltered([]string{"active"})
205+
206+
if err != nil {
207+
t.Fatal(err)
208+
}
209+
210+
unit := getUnitStatus(units, target)
211+
212+
if unit == nil {
213+
t.Fatalf("%s unit not found in list", target)
214+
} else if unit.ActiveState != "active" {
215+
t.Fatalf("Test unit should be active")
216+
}
217+
218+
units, err = conn.ListUnitsFiltered([]string{"inactive"})
219+
220+
if err != nil {
221+
t.Fatal(err)
222+
}
223+
224+
unit = getUnitStatus(units, target)
225+
226+
if unit != nil {
227+
t.Fatalf("Inactive unit should not be found in list")
228+
}
229+
}
230+
231+
// Ensure that ListUnitFilesByPatterns works.
232+
func TestListUnitFilesByPatterns(t *testing.T) {
233+
target1 := "systemd-journald.service"
234+
target2 := "exit.target"
235+
236+
conn := setupConn(t)
237+
238+
units, err := conn.ListUnitFilesByPatterns([]string{"static"}, []string{"systemd-journald*", target2})
239+
240+
if err != nil {
241+
t.Skip(err)
242+
}
243+
244+
unit := getUnitFile(units, target1)
245+
246+
if unit == nil {
247+
t.Fatalf("%s unit not found in list", target1)
248+
} else if unit.Type != "static" {
249+
t.Fatalf("Test unit file should be static")
250+
}
251+
252+
units, err = conn.ListUnitFilesByPatterns([]string{"disabled"}, []string{"systemd-journald*", target2})
253+
254+
if err != nil {
255+
t.Fatal(err)
256+
}
257+
258+
unit = getUnitFile(units, target2)
259+
260+
if unit == nil {
261+
t.Fatalf("%s unit not found in list", target2)
262+
} else if unit.Type != "disabled" {
263+
t.Fatalf("%s unit file should be disabled", target2)
264+
}
265+
}
266+
267+
func TestListUnitFiles(t *testing.T) {
268+
target1 := "systemd-journald.service"
269+
target2 := "exit.target"
270+
271+
conn := setupConn(t)
272+
273+
units, err := conn.ListUnitFiles()
274+
275+
if err != nil {
276+
t.Fatal(err)
277+
}
278+
279+
unit := getUnitFile(units, target1)
280+
281+
if unit == nil {
282+
t.Fatalf("%s unit not found in list", target1)
283+
} else if unit.Type != "static" {
284+
t.Fatalf("Test unit file should be static")
285+
}
286+
287+
unit = getUnitFile(units, target2)
288+
289+
if unit == nil {
290+
t.Fatalf("%s unit not found in list", target2)
291+
} else if unit.Type != "disabled" {
292+
t.Fatalf("%s unit file should be disabled", target2)
293+
}
294+
}
295+
133296
// Enables a unit and then immediately tears it down
134297
func TestEnableDisableUnit(t *testing.T) {
135298
target := "enable-disable.service"
@@ -298,18 +461,11 @@ func TestStartStopTransientUnit(t *testing.T) {
298461

299462
units, err := conn.ListUnits()
300463

301-
var unit *UnitStatus
302-
for _, u := range units {
303-
if u.Name == target {
304-
unit = &u
305-
}
306-
}
464+
unit := getUnitStatus(units, target)
307465

308466
if unit == nil {
309467
t.Fatalf("Test unit not found in list")
310-
}
311-
312-
if unit.ActiveState != "active" {
468+
} else if unit.ActiveState != "active" {
313469
t.Fatalf("Test unit not active")
314470
}
315471

@@ -324,12 +480,7 @@ func TestStartStopTransientUnit(t *testing.T) {
324480

325481
units, err = conn.ListUnits()
326482

327-
unit = nil
328-
for _, u := range units {
329-
if u.Name == target {
330-
unit = &u
331-
}
332-
}
483+
unit = getUnitStatus(units, target)
333484

334485
if unit != nil {
335486
t.Fatalf("Test unit found in list, should be stopped")

test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ split=(${TEST// / })
5757
TEST=${split[@]/#/${REPO_PATH}/}
5858

5959
echo "Running tests..."
60-
go test ${COVER} $@ ${TEST}
60+
go test -v ${COVER} $@ ${TEST}
6161

6262
echo "Checking gofmt..."
6363
fmtRes=$(gofmt -l $FMT)

0 commit comments

Comments
 (0)