-
Zygmunt Krynicki authored
Signed-off-by:
Zygmunt Krynicki <zygmunt.krynicki@huawei.com>
Zygmunt Krynicki authoredSigned-off-by:
Zygmunt Krynicki <zygmunt.krynicki@huawei.com>
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
service_test.go 10.49 KiB
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Huawei Inc.
package service_test
import (
"errors"
"testing"
"booting.oniroproject.org/distro/components/sysota/boot"
"booting.oniroproject.org/distro/components/sysota/boot/testboot"
"booting.oniroproject.org/distro/components/sysota/dbusutil"
"booting.oniroproject.org/distro/components/sysota/dbusutil/dbustest"
"booting.oniroproject.org/distro/components/sysota/ota"
"booting.oniroproject.org/distro/components/sysota/service"
"github.com/godbus/dbus/v5"
. "gopkg.in/check.v1"
)
func Test(t *testing.T) { TestingT(t) }
var errBoom = errors.New("boom")
type serviceSuite struct {
dbustest.Suite
config ota.Config
state ota.SystemState
svc *service.Service
conn *dbus.Conn
}
var _ = Suite(&serviceSuite{})
func (s *serviceSuite) EnsureConn(c *C) *dbus.Conn {
var err error
if s.conn == nil {
s.conn, err = dbusutil.SystemBus()
c.Assert(err, IsNil)
}
return s.conn
}
type stater struct {
config *ota.Config
state *ota.SystemState
}
func (c *stater) LoadConfig() (*ota.Config, error) {
return c.config, nil
}
func (c *stater) SaveConfig(config *ota.Config) error {
return nil
}
func (c *stater) LoadState() (*ota.SystemState, error) {
return c.state, nil
}
func (c *stater) SaveState(state *ota.SystemState) error {
return nil
}
func (s *serviceSuite) EnsureService(c *C) {
var err error
if s.svc == nil {
s.EnsureConn(c)
s.svc, err = service.New(&stater{config: &s.config, state: &s.state}, s.conn)
c.Assert(err, IsNil)
err := s.svc.Export()
c.Assert(err, IsNil)
err = service.RequestBusName(s.conn)
c.Assert(err, IsNil)
}
}
func (s *serviceSuite) SetUpTest(c *C) {
s.config = ota.Config{
DeviceMaker: "test-maker",
DeviceModel: "test-model",
UpdateStream: "test-stream",
}
s.state = ota.SystemState{}
}
func (s *serviceSuite) TearDownTest(c *C) {
if s.svc != nil {
err := s.svc.Unexport()
c.Assert(err, IsNil)
s.svc = nil
}
if s.conn != nil {
err := s.conn.Close()
c.Assert(err, IsNil)
s.conn = nil
}
}
func (s *serviceSuite) TestSmokeAccessWithoutBootProtocolAcrossDBus(c *C) {
s.config.DebugBootAPI = true
s.EnsureService(c)
svcObject := s.conn.Object("org.oniroproject.sysota1", "/org/oniroproject/sysota1/Service")
var slotName string
err := svcObject.Call("org.oniroproject.sysota1.BootLoader.QueryActive", 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boot protocol is not set`)
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.QueryInactive", 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boot protocol is not set`)
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.TrySwitch", 0, "B").Store(&slotName)
c.Assert(err, ErrorMatches, `boot protocol is not set`)
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.CommitSwitch", 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boot protocol is not set`)
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.CancelSwitch", 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boot protocol is not set`)
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.Reboot", 0, 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boot protocol is not set`)
}
func (s *serviceSuite) TestSmokeAccessWithBootProtocolAcrossDBus(c *C) {
var proto testboot.Protocol
s.config.BootLoaderType = ota.TestBoot
s.config.DebugBootAPI = true
service.SetTestBootProtocol(&proto)
s.EnsureService(c)
svcObject := s.conn.Object("org.oniroproject.sysota1", "/org/oniroproject/sysota1/Service")
var slotName string
proto.QueryActiveFn = func() (boot.Slot, error) { return boot.SlotA, nil }
err := svcObject.Call("org.oniroproject.sysota1.BootLoader.QueryActive", 0).Store(&slotName)
c.Assert(err, IsNil)
c.Check(slotName, Equals, "A")
proto.QueryActiveFn = func() (boot.Slot, error) { return boot.InvalidSlot, errBoom }
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.QueryActive", 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boom`)
proto.QueryInactiveFn = func() (boot.Slot, error) { return boot.SlotB, nil }
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.QueryInactive", 0).Store(&slotName)
c.Assert(err, IsNil)
c.Check(slotName, Equals, "B")
proto.QueryInactiveFn = func() (boot.Slot, error) { return boot.InvalidSlot, errBoom }
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.QueryInactive", 0).Store(&slotName)
c.Assert(err, ErrorMatches, `boom`)
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.TrySwitch", 0, "potato").Store()
c.Assert(err, ErrorMatches, `invalid boot slot`)
called := false
proto.TrySwitchFn = func(slot boot.Slot) error {
called = true
c.Check(slot, Equals, boot.SlotB)
return nil
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.TrySwitch", 0, "B").Store()
c.Assert(err, IsNil)
c.Check(called, Equals, true)
proto.TrySwitchFn = func(_ boot.Slot) error {
return errBoom
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.TrySwitch", 0, "B").Store()
c.Assert(err, ErrorMatches, `boom`)
called = false
proto.CommitSwitchFn = func() error {
called = true
return nil
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.CommitSwitch", 0).Store()
c.Assert(err, IsNil)
c.Check(called, Equals, true)
proto.CommitSwitchFn = func() error {
return errBoom
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.CommitSwitch", 0).Store()
c.Assert(err, ErrorMatches, `boom`)
called = false
proto.CancelSwitchFn = func() error {
called = true
return nil
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.CancelSwitch", 0).Store()
c.Assert(err, IsNil)
c.Check(called, Equals, true)
proto.CancelSwitchFn = func() error {
return errBoom
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.CancelSwitch", 0).Store()
c.Assert(err, ErrorMatches, `boom`)
called = false
proto.RebootFn = func(flags boot.RebootFlags) error {
called = true
c.Check(flags, Equals, boot.RebootTryBoot)
return nil
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.Reboot", 0, boot.RebootTryBoot).Store()
c.Assert(err, IsNil)
c.Check(called, Equals, true)
proto.RebootFn = func(flags boot.RebootFlags) error {
return errBoom
}
err = svcObject.Call("org.oniroproject.sysota1.BootLoader.Reboot", 0, 0).Store()
c.Assert(err, ErrorMatches, `boom`)
}
func (s *serviceSuite) TestAccessPropertiesAcrossDBus(c *C) {
s.EnsureService(c)
svcObject := s.conn.Object("org.oniroproject.sysota1", "/org/oniroproject/sysota1/Service")
var propValue dbus.Variant
err := svcObject.Call("org.freedesktop.DBus.Properties.Get", 0, "org.oniroproject.sysota1.Service", "Maker").Store(&propValue)
c.Assert(err, IsNil)
c.Check(propValue, Equals, dbus.MakeVariant("test-maker"))
err = svcObject.Call("org.freedesktop.DBus.Properties.Get", 0, "org.oniroproject.sysota1.Service", "Model").Store(&propValue)
c.Assert(err, IsNil)
c.Check(propValue, Equals, dbus.MakeVariant("test-model"))
err = svcObject.Call("org.freedesktop.DBus.Properties.Get", 0, "org.oniroproject.sysota1.Service", "Stream").Store(&propValue)
c.Assert(err, IsNil)
c.Check(propValue, Equals, dbus.MakeVariant("test-stream"))
err = svcObject.Call("org.freedesktop.DBus.Properties.Get", 0, "org.oniroproject.sysota1.Service", "Potato").Store(&propValue)
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.PropertyNotFound`)
err = svcObject.Call("org.freedesktop.DBus.Properties.Get", 0, "org.oniroproject.sysota1.Potato", "Property").Store(&propValue)
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.InterfaceNotFound`)
var propMap map[string]dbus.Variant
err = svcObject.Call("org.freedesktop.DBus.Properties.GetAll", 0, "org.oniroproject.sysota1.Service").Store(&propMap)
c.Assert(err, IsNil)
c.Check(propMap, DeepEquals, map[string]dbus.Variant{
"Maker": dbus.MakeVariant("test-maker"),
"Model": dbus.MakeVariant("test-model"),
"Stream": dbus.MakeVariant("test-stream"),
})
err = svcObject.Call("org.freedesktop.DBus.Properties.GetAll", 0, "org.oniroproject.sysota1.Potato").Store(&propMap)
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.InterfaceNotFound`)
err = svcObject.Call("org.freedesktop.DBus.Properties.Set", 0, "org.oniroproject.sysota1.Service", "Maker", "potato").Store()
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.ReadOnly`)
err = svcObject.Call("org.freedesktop.DBus.Properties.Set", 0, "org.oniroproject.sysota1.Service", "Model", "potato").Store()
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.ReadOnly`)
// Stream can be changed.
// TODO(zyga): observe the property changed signal.
err = svcObject.Call("org.freedesktop.DBus.Properties.Set", 0, "org.oniroproject.sysota1.Service", "Stream", "new-stream").Store()
c.Assert(err, IsNil)
err = svcObject.Call("org.freedesktop.DBus.Properties.Get", 0, "org.oniroproject.sysota1.Service", "Stream").Store(&propValue)
c.Assert(err, IsNil)
c.Check(propValue, Equals, dbus.MakeVariant("new-stream"))
err = svcObject.Call("org.freedesktop.DBus.Properties.Set", 0, "org.oniroproject.sysota1.Service", "Stream", 42).Store()
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.InvalidArg`)
err = svcObject.Call("org.freedesktop.DBus.Properties.Set", 0, "org.oniroproject.sysota1.Service", "Potato", "value").Store()
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.PropertyNotFound`)
err = svcObject.Call("org.freedesktop.DBus.Properties.Set", 0, "org.oniroproject.sysota1.Potato", "Property", "value").Store()
c.Assert(err, ErrorMatches, `org.freedesktop.DBus.Properties.Error.InterfaceNotFound`)
}
func (s *serviceSuite) TestIsIdle(c *C) {
s.EnsureService(c)
// Service without operations is idle.
c.Check(s.svc.IsIdle(), Equals, true)
}
func (s *serviceSuite) TestGetManagedObjects(c *C) {
s.EnsureService(c)
svcObject := s.conn.Object("org.oniroproject.sysota1", "/org/oniroproject/sysota1/Service")
var objs map[dbus.ObjectPath]map[string]map[string]dbus.Variant
err := svcObject.Call("org.freedesktop.DBus.ObjectManager.GetManagedObjects", 0).Store(&objs)
c.Assert(err, IsNil)
c.Check(objs, DeepEquals, map[dbus.ObjectPath]map[string]map[string]dbus.Variant{})
}
func (s *serviceSuite) TestBootMode(c *C) {
s.EnsureService(c)
c.Check(s.svc.BootMode(), Equals, boot.Normal)
// TODO(zyga): check that PropertiesChanged signal was *not* sent.
c.Check(s.svc.SetBootMode(boot.Mode(boot.Normal)), IsNil)
// TODO(zyga): check that PropertiesChanged signal was sent.
c.Check(s.svc.SetBootMode(boot.Mode(ota.TestBoot)), IsNil)
c.Check(s.svc.BootMode(), Equals, boot.Try)
}