blob: 0869f1344874be86ca61c7c53a30000f6172a109 [file] [log] [blame]
// Copyright 2021 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package wifi
import (
"context"
"strconv"
"time"
"go.chromium.org/tast-tests/cros/common/network/ping"
"go.chromium.org/tast-tests/cros/common/tbdep"
tdreq "go.chromium.org/tast-tests/cros/common/testdevicerequirements"
"go.chromium.org/tast-tests/cros/common/wifi/security/wpa"
"go.chromium.org/tast-tests/cros/common/wifi/security/wpaeap"
"go.chromium.org/tast-tests/cros/remote/bundles/cros/wifi/wifiutil"
remoteping "go.chromium.org/tast-tests/cros/remote/network/ping"
"go.chromium.org/tast-tests/cros/remote/wificell"
"go.chromium.org/tast-tests/cros/remote/wificell/hostapd"
"go.chromium.org/tast-tests/cros/remote/wificell/verifier"
"go.chromium.org/tast/core/ctxutil"
"go.chromium.org/tast/core/testing"
"go.chromium.org/tast/core/testing/hwdep"
)
type pingParam struct {
opts []ping.Option
// Max packets lost per roaming round.
maxLoss int
}
func init() {
testing.AddTest(&testing.Test{
Func: RoamContPing,
Desc: "Send ping every 10ms and check how many packets are lost on average during roaming",
Contacts: []string{
"chromeos-wifi-champs@google.com", // WiFi oncall rotation
},
BugComponent: "b:893827", // ChromeOS > Platform > Connectivity > WiFi
Attr: []string{"group:wificell", "wificell_perf", "wificell_unstable"},
TestBedDeps: []string{
tbdep.Wificell,
tbdep.WifiStateNormal,
tbdep.BluetoothStateNormal,
tbdep.PeripheralWifiStateWorking,
// TODO(b/319149188) Replace this with a feature requirement once available.
tbdep.WifiRouterModels("OPENWRT[Ubiquiti_UniFi_6_Lite]")[0],
},
ServiceDeps: []string{wificell.ShillServiceName},
// A single DHCP server sharing same address pool for clients
// connected to either AP is needed, so that a setup with bridges
// and veths is used.
Fixture: wificell.FixtureID(wificell.TFFeaturesBridgeAndVeth | wificell.TFFeaturesCapture),
Requirements: []string{tdreq.WiFiGenSupportWiFi, tdreq.WiFiProcPassFW, tdreq.WiFiProcPassAVL, tdreq.WiFiProcPassAVLBeforeUpdates},
Timeout: time.Minute * 5, // The average test time doubled.
Vars: []string{"wifi.RoamContPing.rounds"},
Params: []testing.Param{{
Name: "none",
Val: wifiutil.ContParam{
Rounds: 50,
ApOpts: [2][]hostapd.Option{{hostapd.Channel(1), hostapd.Mode(hostapd.Mode80211g)},
{hostapd.Channel(157), hostapd.Mode(hostapd.Mode80211acPure), hostapd.HTCaps(hostapd.HTCapHT40Plus), hostapd.VHTCaps(hostapd.VHTCapSGI80),
hostapd.VHTChWidth(hostapd.VHTChWidth80), hostapd.VHTCenterChannel(155)}},
Param: pingParam{
opts: []ping.Option{ping.Count(1000), ping.Interval(0.01)},
// With 10ms ping interval, abnormal time without service would be 25 packets = 250ms.
maxLoss: 25,
},
},
}, {
Name: "psk",
Val: wifiutil.ContParam{
Rounds: 50,
ApOpts: [2][]hostapd.Option{{hostapd.Channel(1), hostapd.Mode(hostapd.Mode80211g)},
{hostapd.Channel(157), hostapd.Mode(hostapd.Mode80211acPure), hostapd.HTCaps(hostapd.HTCapHT40Plus), hostapd.VHTCaps(hostapd.VHTCapSGI80),
hostapd.VHTChWidth(hostapd.VHTChWidth80), hostapd.VHTCenterChannel(155)}},
SecConfFac: wpa.NewConfigFactory("chromeos", wpa.Mode(wpa.ModePureWPA2), wpa.Ciphers2(wpa.CipherCCMP)),
Param: pingParam{
opts: []ping.Option{ping.Count(1000), ping.Interval(0.01)},
maxLoss: 25,
},
},
}, {
Name: "ft_psk",
ExtraHardwareDeps: hwdep.D(hwdep.WifiFT()),
Val: wifiutil.ContParam{
Rounds: 50,
ApOpts: [2][]hostapd.Option{{hostapd.Channel(1), hostapd.Mode(hostapd.Mode80211g)},
{hostapd.Channel(157), hostapd.Mode(hostapd.Mode80211acPure), hostapd.HTCaps(hostapd.HTCapHT40Plus), hostapd.VHTCaps(hostapd.VHTCapSGI80),
hostapd.VHTChWidth(hostapd.VHTChWidth80), hostapd.VHTCenterChannel(155)}},
SecConfFac: wpa.NewConfigFactory("chromeos", wpa.Mode(wpa.ModePureWPA2), wpa.Ciphers2(wpa.CipherCCMP), wpa.FTMode(wpa.FTModePure)),
EnableFT: true,
Param: pingParam{
opts: []ping.Option{ping.Count(1000), ping.Interval(0.01)},
maxLoss: 25,
},
},
}, {
Name: "eap",
Val: wifiutil.ContParam{
Rounds: 50,
ApOpts: [2][]hostapd.Option{{hostapd.Channel(1), hostapd.Mode(hostapd.Mode80211g)},
{hostapd.Channel(157), hostapd.Mode(hostapd.Mode80211acPure), hostapd.HTCaps(hostapd.HTCapHT40Plus), hostapd.VHTCaps(hostapd.VHTCapSGI80),
hostapd.VHTChWidth(hostapd.VHTChWidth80), hostapd.VHTCenterChannel(155)}},
SecConfFac: wpaeap.NewConfigFactory(
wifiutil.Cert1.CACred.Cert, wifiutil.Cert1.ServerCred,
wpaeap.ClientCACert(wifiutil.Cert1.CACred.Cert), wpaeap.ClientCred(wifiutil.Cert1.ClientCred),
wpaeap.Mode(wpa.ModePureWPA2),
),
Param: pingParam{
opts: []ping.Option{ping.Count(1000), ping.Interval(0.01)},
maxLoss: 25,
},
},
}, {
Name: "ft_eap",
ExtraHardwareDeps: hwdep.D(hwdep.WifiFT()),
Val: wifiutil.ContParam{
Rounds: 50,
ApOpts: [2][]hostapd.Option{{hostapd.Channel(1), hostapd.Mode(hostapd.Mode80211g)},
{hostapd.Channel(157), hostapd.Mode(hostapd.Mode80211acPure), hostapd.HTCaps(hostapd.HTCapHT40Plus), hostapd.VHTCaps(hostapd.VHTCapSGI80),
hostapd.VHTChWidth(hostapd.VHTChWidth80), hostapd.VHTCenterChannel(155)}},
SecConfFac: wpaeap.NewConfigFactory(
wifiutil.Cert1.CACred.Cert, wifiutil.Cert1.ServerCred,
wpaeap.ClientCACert(wifiutil.Cert1.CACred.Cert), wpaeap.ClientCred(wifiutil.Cert1.ClientCred),
wpaeap.Mode(wpa.ModePureWPA2), wpaeap.FTMode(wpa.FTModePure),
),
EnableFT: true,
Param: pingParam{
opts: []ping.Option{ping.Count(1000), ping.Interval(0.01)},
maxLoss: 25,
},
},
}},
})
}
func RoamContPing(ctx context.Context, s *testing.State) {
tf := s.FixtValue().(*wificell.TestFixture)
param := s.Param().(wifiutil.ContParam)
// Allow override
var rounds int
roundsStr, ok := s.Var("wifi.RoamContPing.rounds")
if !ok {
rounds = param.Rounds
} else {
var err error
rounds, err = strconv.Atoi(roundsStr)
if err != nil {
s.Fatal("Failed to convert value, err: ", err)
}
}
ctx, ct, finish, err := wifiutil.ContinuityTestInitialSetup(ctx, tf, param)
if err != nil {
s.Fatal("Failed initial setup of the test: ", err)
}
defer func() {
if err := finish(); err != nil {
s.Error("Error while tearing down test setup: ", err)
}
}()
ctx, cancel := ctxutil.Shorten(ctx, 10*time.Second)
defer cancel()
var vf *verifier.Verifier
var resultAssertF func(context.Context, []verifier.ResultType)
pingF := func(ctx context.Context) (verifier.ResultType, error) {
iface, err := tf.ClientInterface(ctx)
if err != nil {
s.Fatal("DUT: failed to get the client WiFi interface: ", err)
}
opts := param.Param.(pingParam).opts
// Bind ping used in all WiFi Tests to WiFiInterface. Otherwise if the
// WiFi interface is not up yet they will be routed through the Ethernet
// interface. Also see b/225205611 for details.
opts = append(opts, ping.BindAddress(true), ping.SourceIface(iface))
// We need more result data than a simple tf.PingFromDUT(), so we use a separate runner.
pr := remoteping.NewRemoteRunner(s.DUT().Conn())
res, err := pr.Ping(ctx, wifiutil.ServerIP(), opts...)
if err != nil {
testing.ContextLog(ctx, "ping error: ", err)
return verifier.ResultType{}, err
}
testing.ContextLogf(ctx, "Continuity: ping statistics=%+v", res)
return verifier.ResultType{Data: res, Timestamp: time.Now()}, nil
}
resultAssertF = func(ctx context.Context, results []verifier.ResultType) {
var sent, received int
for i, ret := range results {
pingData := ret.Data.(*ping.Result)
testing.ContextLogf(ctx, "Iteration %d: End Time=%s, Packets lost=%d",
i+1, ret.Timestamp.Format("15:04:05.000"), pingData.Sent-pingData.Received)
sent += pingData.Sent
received += pingData.Received
}
loss := sent - received
testing.ContextLogf(ctx, "Total packets lost=%d/%d (%d per round)",
loss, sent, loss/rounds)
if loss > rounds*param.Param.(pingParam).maxLoss {
s.Fatal("Loss threshold exceeded")
}
}
vf = verifier.NewVerifier(ctx, pingF)
defer vf.Finish()
ctx, cancel = ctxutil.Shorten(ctx, time.Second)
defer cancel()
ctx, destroy, err := ct.ContinuityTestSetupFinalize(ctx)
if err != nil {
s.Fatal("Failed finalization of the setup of the test: ", err)
}
defer func() {
if err := destroy(); err != nil {
s.Error("Error while tearing down test setup: ", err)
}
}()
ctx, cancel = ctxutil.Shorten(ctx, time.Second)
defer cancel()
vf.StartJob()
for i := 0; i < rounds; i++ {
if err := ct.ContinuityRound(ctx, i); err != nil {
s.Fatal("Error in continuity round: ", err)
}
}
results, err := vf.StopJob()
if err != nil {
s.Fatal("Error while receiving verification results, err: ", err)
return
}
resultAssertF(ctx, results)
}