blob: 7c048dfa3120e1bb7dc24564356d23522b1ad30e [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 wifi
import (
"context"
"time"
"chromiumos/tast/common/shillconst"
"chromiumos/tast/remote/wificell"
"chromiumos/tast/remote/wificell/hostapd"
"chromiumos/tast/services/cros/wifi"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: CSAReconnect,
Desc: "Verifies that DUT will switch to the new channel after the AP starts a CSA",
Contacts: []string{
"arowa@google.com", // Test author
"chromeos-wifi-champs@google.com", // WiFi oncall rotation; or http://b/new?component=893827
},
Attr: []string{"group:wificell", "wificell_func", "wificell_unstable"},
ServiceDeps: []string{wificell.TFServiceName},
Fixture: "wificellFixt",
})
}
func CSAReconnect(ctx context.Context, s *testing.State) {
const (
primaryChannel = 64
alterChannel = 36
)
tf := s.FixtValue().(*wificell.TestFixture)
apOps := []hostapd.Option{hostapd.Mode(hostapd.Mode80211nMixed), hostapd.Channel(primaryChannel), hostapd.HTCaps(hostapd.HTCapHT20)}
ap, err := tf.ConfigureAP(ctx, apOps, nil)
if err != nil {
s.Fatal("Failed to configure AP: ", err)
}
defer func(ctx context.Context) {
if err := tf.DeconfigAP(ctx, ap); err != nil {
s.Error("Failed to deconfig AP: ", err)
}
}(ctx)
s.Log("AP setup done")
ctx, cancel := tf.ReserveForDeconfigAP(ctx, ap)
defer cancel()
// Connect to the AP.
var servicePath string
ctxForDisconnect := ctx
ctx, cancel = tf.ReserveForDisconnect(ctx)
defer cancel()
if resp, err := tf.ConnectWifiAP(ctx, ap); err != nil {
s.Fatal("DUT: failed to connect to WiFi: ", err)
} else {
servicePath = resp.ServicePath
}
defer func(ctx context.Context) {
if err := tf.CleanDisconnectWifi(ctx); err != nil {
s.Error("DUT: failed to disconnect WiFi: ", err)
}
}(ctxForDisconnect)
s.Log("Connected")
// Assert connection.
if err := tf.VerifyConnection(ctx, ap); err != nil {
s.Fatal("Failed to verify connection: ", err)
}
alterFreq, err := hostapd.ChannelToFrequency(alterChannel)
if err != nil {
s.Fatal("Failed to get server frequency: ", err)
}
props := []*wificell.ShillProperty{
{
Property: shillconst.ServicePropertyWiFiFrequency,
ExpectedValues: []interface{}{uint32(alterFreq)},
Method: wifi.ExpectShillPropertyRequest_CHECK_WAIT,
},
}
waitCtx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
monitorProps := []string{shillconst.ServicePropertyIsConnected}
waitForProps, err := tf.WifiClient().ExpectShillProperty(waitCtx, servicePath, props, monitorProps)
if err != nil {
s.Fatal("DUT: failed to create a property watcher, err: ", err)
}
// Router starts ChannelSwitching.
csaStart := time.Now()
if err := ap.StartChannelSwitch(ctx, 8, alterChannel, hostapd.CSAMode("ht")); err != nil {
s.Fatal("Failed to send CSA from AP: ", err)
}
s.Log("CSA frame was sent from the AP")
monitorResult, err := waitForProps()
if err != nil {
s.Fatal("DUT: failed to wait for the properties, err: ", err)
}
s.Log("DUT: switched channel")
// Assert there was no disconnection during channel switching.
for _, ph := range monitorResult {
if ph.Name == shillconst.ServicePropertyIsConnected {
if !ph.Value.(bool) {
// TODO(b/181365077): Gale AP takes a long time to send beacons on the new channel and that
// causes the DUT to abort the CSA process. After this issue is fixed, the test should fail
// if a disconnection is detected.
s.Log("DUT: failed to stay connected during the channel switching process")
}
}
}
// Assert connection.
if err := testing.Poll(ctx, func(ctx context.Context) error {
return tf.VerifyConnection(ctx, ap)
}, &testing.PollOptions{
Timeout: 20 * time.Second,
Interval: time.Second,
}); err != nil {
s.Fatal("Failed to verify connection: ", err)
}
s.Log("Connection verified after CSA; elapsed time:", time.Since(csaStart))
}