blob: e43efc3e200d6e8d8601a176b70653ef04510399 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package shill
import (
"context"
"time"
"github.com/godbus/dbus"
"chromiumos/tast/common/shillconst"
"chromiumos/tast/errors"
"chromiumos/tast/testing"
)
const (
dbusServiceInterface = "org.chromium.flimflam.Service"
)
// Service wraps a Service D-Bus object in shill.
type Service struct {
*PropertyHolder
}
// NewService connects to a service in Shill.
func NewService(ctx context.Context, path dbus.ObjectPath) (*Service, error) {
ph, err := NewPropertyHolder(ctx, dbusService, dbusServiceInterface, path)
if err != nil {
return nil, err
}
return &Service{PropertyHolder: ph}, nil
}
// GetDevice returns the Device object corresponding to the Service object
func (s *Service) GetDevice(ctx context.Context) (*Device, error) {
serviceProps, err := s.GetProperties(ctx)
if err != nil {
return nil, err
}
deviceObjPath, err := serviceProps.GetObjectPath(shillconst.ServicePropertyDevice)
if err != nil {
return nil, errors.Wrap(err, "no device associated with service")
}
device, err := NewDevice(ctx, deviceObjPath)
if err != nil {
return nil, err
}
return device, nil
}
// IsConnected returns true if the the service is connected.
func (s *Service) IsConnected(ctx context.Context) (bool, error) {
props, err := s.GetProperties(ctx)
if err != nil {
return false, errors.Wrap(err, "unable to get properties")
}
connected, err := props.GetBool(shillconst.ServicePropertyIsConnected)
if err != nil {
return false, errors.Wrap(err, "unable to get IsConnected from properties")
}
return connected, nil
}
// WaitForConnectedOrError polls for either:
// * Service.IsConnected to be true, in which case nil is returned.
// * Service.Error to be set to an error value, in which case that is returned as an error.
// Any failure also returns an error.
func (s *Service) WaitForConnectedOrError(ctx context.Context) error {
errorStr := ""
pollErr := testing.Poll(ctx, func(ctx context.Context) error {
props, err := s.GetShillProperties(ctx)
if err != nil {
return err
}
connected, err := props.Get(shillconst.ServicePropertyIsConnected)
if err != nil {
return err
}
if connected.(bool) {
return nil
}
errorVal, err := props.Get(shillconst.ServicePropertyError)
if err != nil {
return err
}
errorStr = errorVal.(string)
// Treat "no-failure" Error values as empty values.
if errorStr == shillconst.ServiceErrorNoFailure {
errorStr = ""
}
if errorStr != "" {
return nil
}
return errors.New("not connected and no error")
}, &testing.PollOptions{
Timeout: shillconst.DefaultTimeout,
Interval: 100 * time.Millisecond,
})
if pollErr != nil {
return pollErr
}
if errorStr != "" {
return errors.New(errorStr)
}
return nil
}
// Connect calls the Connect method on the service.
func (s *Service) Connect(ctx context.Context) error {
return s.Call(ctx, "Connect").Err
}
// Disconnect calls the Disconnect method on the service.
func (s *Service) Disconnect(ctx context.Context) error {
return s.Call(ctx, "Disconnect").Err
}
// Remove calls the Remove method on the service.
func (s *Service) Remove(ctx context.Context) error {
return s.Call(ctx, "Remove").Err
}