blob: 63f6a9a14266dddd396822f687e1f52cc1080f54 [file] [log] [blame]
// Copyright 2020 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 assistant
import (
func init() {
Func: WifiQueries,
Desc: "Tests toggling WiFi using Assistant queries",
Contacts: []string{"", ""},
Attr: []string{"group:mainline", "informational"},
SoftwareDeps: []string{"chrome", "shill-wifi"},
Pre: assistant.VerboseLoggingEnabled(),
// WifiQueries tests that Assistant queries can be used to toggle WiFi on/off
func WifiQueries(ctx context.Context, s *testing.State) {
cr := s.PreValue().(*chrome.Chrome)
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Creating test API connection failed: ", err)
// Enable the Assistant and wait for the ready signal.
if err := assistant.EnableAndWaitForReady(ctx, tconn); err != nil {
s.Fatal("Failed to enable Assistant: ", err)
defer assistant.Disable(ctx, tconn)
// Open the Settings window, where we can verify Wifi button status
if err := apps.Launch(ctx, tconn, apps.Settings.ID); err != nil {
s.Fatal("Failed to launch Settings app: ", err)
// Turn settings on, off, and on again to ensure they can be enabled and disabled, regardless of starting state
statuses := []bool{true, false, true}
var onOff string
for _, status := range statuses {
if status {
onOff = "on"
} else {
onOff = "off"
s.Log("Turning wifi ", onOff)
// assistant.SendTextQuery sometimes times out after the assistant UI is closed,
// so poll to ensure the queries go through.
// TODO(crbug/1080363): remove polling.
if err := testing.Poll(ctx, func(ctx context.Context) error {
_, err := assistant.SendTextQuery(ctx, tconn, fmt.Sprintf("turn wifi %v", onOff))
return err
}, nil); err != nil {
s.Fatal("Failed to get Assistant wifi query response: ", err)
s.Log("Checking wifi status")
if err := expectWifiEnabled(ctx, status); err != nil {
s.Fatal("Wifi status was not changed by the assistant query: ", err)
// Check if button in the Settings app UI updated to match the actual status.
// The buttons don't update immediately, so we'll need to poll their statuses.
// The "aria-pressed" htmlAttribute of the toggle buttons can be used to check the on/off status
s.Log("Checking wifi toggle button status")
if err := testing.Poll(ctx, func(ctx context.Context) error {
params := ui.FindParams{Name: "Wi-Fi enable", Role: ui.RoleTypeToggleButton}
wifiToggle, err := ui.FindWithTimeout(ctx, tconn, params, 10*time.Second)
if err != nil {
return testing.PollBreak(err)
defer wifiToggle.Release(ctx)
if wifiToggle.HTMLAttributes["aria-pressed"] != strconv.FormatBool(status) {
return errors.Errorf("wifi not toggled yet, aria-pressed is %v, expected %v",
wifiToggle.HTMLAttributes["aria-pressed"], status)
return nil
}, nil); err != nil {
s.Fatal("WiFi toggle button in the Settings app was not toggled by the Assistant query: ", err)
// expectWifiEnabled uses shill to check if Wifi is in the expected state
func expectWifiEnabled(ctx context.Context, expectEnabled bool) error {
m, err := shill.NewManager(ctx)
if err != nil {
return errors.Wrap(err, "failed to get shill manager")
watcher, err := m.CreateWatcher(ctx)
if err != nil {
return errors.Wrap(err, "failed to create a PropertiesWatcher")
defer watcher.Close(ctx)
for {
prop, err := m.GetProperties(ctx)
technologies, err := prop.GetStrings(shillconst.ManagerPropertyEnabledTechnologies)
if err != nil {
return errors.Wrap(err, "failed to get enabled technologies")
found := false
for _, t := range technologies {
if t == string(shill.TechnologyWifi) {
found = true
if expectEnabled == found {
return nil
// If the Wifi status is not what we expect, check again when the enabled technologies property changes.
if _, err := watcher.WaitAll(ctx, shillconst.ManagerPropertyEnabledTechnologies); err != nil {
return errors.Wrap(err, "failed waiting for enabled technologies to change")