Migrate ChannelSweepTest to generate_tests
Migrate away from the deprecated ACTS self.run_generated_testcases
method to the Mobly self.generate_tests method. Doing this has increased
readability of the test class and allow for easy adding/removing of
parameters to permeate with.
Rework how throughput CSV and HTML files are being generated. These
files are now generated at the end of the test.
Rework verification of throughput standard deviation. Implement a new
test called "test_standard_deviation" that looks through all previous
test results and calculate the standard deviation for each
county/security/bandwidth combo across all channels. This test is
guaranteed to run last.
Move regulatory_channels.py into the antlion package such that multiple
tests can use the registry of WLAN channels.
Fixed: b/281582355
Bug: b/274619290
Change-Id: I9c1eca85974b0e12191cf18c9742d96b84c49b2e
Reviewed-on: https://fuchsia-review.googlesource.com/c/antlion/+/869279
Reviewed-by: Hayden Nix <haydennix@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
Fuchsia-Auto-Submit: Sam Balana <sbalana@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 01a7d53..a044311 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -81,6 +81,7 @@
"controllers/ap_lib/radvd.py",
"controllers/ap_lib/radvd_config.py",
"controllers/ap_lib/radvd_constants.py",
+ "controllers/ap_lib/regulatory_channels.py",
"controllers/ap_lib/third_party_ap_profiles/__init__.py",
"controllers/ap_lib/third_party_ap_profiles/actiontec.py",
"controllers/ap_lib/third_party_ap_profiles/asus.py",
@@ -219,6 +220,7 @@
"test_utils/wifi/wifi_performance_test_utils/qcom_utils.py",
"test_utils/wifi/wifi_test_utils.py",
"tracelogger.py",
+ "typing.py",
"utils.py",
]
library_deps = [
diff --git a/tests/wlan/compliance/regulatory_channels.py b/packages/antlion/controllers/ap_lib/regulatory_channels.py
similarity index 100%
rename from tests/wlan/compliance/regulatory_channels.py
rename to packages/antlion/controllers/ap_lib/regulatory_channels.py
diff --git a/pyproject.toml b/pyproject.toml
index 1cf1b5d..391c35d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -82,7 +82,6 @@
"tests/wlan/functional/SoftApTest.py",
"tests/wlan/functional/WlanRebootTest.py",
"tests/wlan/functional/WlanWirelessNetworkManagementTest.py",
- "tests/wlan/performance/ChannelSweepTest.py",
"tests/wlan/performance/WlanRvrTest.py",
"tests/wlan/performance/WlanWmmTest.py",
diff --git a/tests/wlan/compliance/BUILD.gn b/tests/wlan/compliance/BUILD.gn
index 8123ffd..98e290e 100644
--- a/tests/wlan/compliance/BUILD.gn
+++ b/tests/wlan/compliance/BUILD.gn
@@ -9,9 +9,6 @@
antlion_host_test("regulatory_compliance_test") {
main_source = "RegulatoryComplianceTest.py"
- sources = [
- "regulatory_channels.py",
- ]
environments = display_ap_envs
}
diff --git a/tests/wlan/compliance/RegulatoryComplianceTest.py b/tests/wlan/compliance/RegulatoryComplianceTest.py
index 56c9756..ace378c 100644
--- a/tests/wlan/compliance/RegulatoryComplianceTest.py
+++ b/tests/wlan/compliance/RegulatoryComplianceTest.py
@@ -18,12 +18,15 @@
from typing import List, NamedTuple, Optional
from mobly import asserts, test_runner
-from regulatory_channels import COUNTRY_CHANNELS, TEST_CHANNELS
from antlion import utils
from antlion.controllers.access_point import setup_ap
from antlion.controllers.ap_lib import hostapd_constants
from antlion.controllers.ap_lib.hostapd_security import Security
+from antlion.controllers.ap_lib.regulatory_channels import (
+ COUNTRY_CHANNELS,
+ TEST_CHANNELS,
+)
from antlion.test_utils.abstract_devices.wlan_device import (
SupportsWLAN,
create_wlan_device,
diff --git a/tests/wlan/performance/BUILD.gn b/tests/wlan/performance/BUILD.gn
index 4f0ab42..4cf391a 100644
--- a/tests/wlan/performance/BUILD.gn
+++ b/tests/wlan/performance/BUILD.gn
@@ -9,7 +9,6 @@
antlion_host_test("channel_sweep_test") {
main_source = "ChannelSweepTest.py"
- test_params = "channel_sweep_test_params.yaml"
environments = display_ap_iperf_envs
}
diff --git a/tests/wlan/performance/ChannelSweepTest.py b/tests/wlan/performance/ChannelSweepTest.py
index 357d660..19e9723 100644
--- a/tests/wlan/performance/ChannelSweepTest.py
+++ b/tests/wlan/performance/ChannelSweepTest.py
@@ -17,80 +17,159 @@
import logging
import os
import time
+from dataclasses import dataclass
+from pathlib import Path
from statistics import pstdev
+from typing import Any, Dict, List, Optional, Tuple
from mobly import asserts, test_runner
-from antlion import context, utils
+from antlion import utils
from antlion.controllers.access_point import setup_ap
-from antlion.controllers.ap_lib import hostapd_config, hostapd_constants
-from antlion.controllers.ap_lib.hostapd_security import Security
+from antlion.controllers.ap_lib import hostapd_constants
+from antlion.controllers.ap_lib.hostapd_security import Security, SecurityMode
+from antlion.controllers.ap_lib.regulatory_channels import COUNTRY_CHANNELS
+from antlion.controllers.iperf_client import IPerfClientOverAdb, IPerfClientOverSsh
from antlion.controllers.iperf_server import IPerfResult
from antlion.test_utils.abstract_devices.wlan_device import create_wlan_device
from antlion.test_utils.wifi import base_test
-N_CAPABILITIES_DEFAULT = [
- hostapd_constants.N_CAPABILITY_LDPC,
- hostapd_constants.N_CAPABILITY_SGI20,
- hostapd_constants.N_CAPABILITY_SGI40,
- hostapd_constants.N_CAPABILITY_TX_STBC,
- hostapd_constants.N_CAPABILITY_RX_STBC1,
-]
-
-AC_CAPABILITIES_DEFAULT = [
- hostapd_constants.AC_CAPABILITY_MAX_MPDU_11454,
- hostapd_constants.AC_CAPABILITY_RXLDPC,
- hostapd_constants.AC_CAPABILITY_SHORT_GI_80,
- hostapd_constants.AC_CAPABILITY_TX_STBC_2BY1,
- hostapd_constants.AC_CAPABILITY_RX_STBC_1,
- hostapd_constants.AC_CAPABILITY_MAX_A_MPDU_LEN_EXP7,
- hostapd_constants.AC_CAPABILITY_RX_ANTENNA_PATTERN,
- hostapd_constants.AC_CAPABILITY_TX_ANTENNA_PATTERN,
-]
-
-DEFAULT_MIN_THROUGHPUT = 0
-DEFAULT_MAX_STD_DEV = 1
+DEFAULT_MIN_THROUGHPUT = 0.0
+DEFAULT_MAX_STD_DEV = 1.0
DEFAULT_IPERF_TIMEOUT = 30
DEFAULT_TIME_TO_WAIT_FOR_IP_ADDR = 30
GRAPH_CIRCLE_SIZE = 10
-IPERF_NO_THROUGHPUT_VALUE = 0
MAX_2_4_CHANNEL = 14
TIME_TO_SLEEP_BETWEEN_RETRIES = 1
-TIME_TO_WAIT_FOR_COUNTRY_CODE = 10
WEP_HEX_STRING_LENGTH = 10
MEGABITS_PER_SECOND = "Mbps"
-def get_test_name(settings):
- """Retrieves the test_name value from test_settings"""
- return settings.get("test_name")
+@dataclass
+class TestParams:
+ country_code: str
+ """Country code for the DUT to set before running the test."""
+
+ security_mode: Optional[SecurityMode]
+ """Security type of the network to create. None represents an open network."""
+
+ channel: int
+ """Channel for the AP to broadcast on"""
+
+ channel_bandwidth: int
+ """Channel bandwidth in MHz for the AP to broadcast with"""
+
+ expect_min_rx_throughput_mbps: float = DEFAULT_MIN_THROUGHPUT
+ """Expected minimum receive throughput in Mb/s"""
+
+ expect_min_tx_throughput_mbps: float = DEFAULT_MIN_THROUGHPUT
+ """Expected minimum transmit throughput in Mb/s"""
+
+ # TODO: Use this value
+ expect_max_std_dev: float = DEFAULT_MAX_STD_DEV
+ """Expected maximum standard deviation of throughput in Mb/s"""
+
+
+@dataclass
+class ThroughputKey:
+ country_code: str
+ security_mode: Optional[SecurityMode]
+ channel_bandwidth: int
+
+ @staticmethod
+ def from_test(test: TestParams) -> "ThroughputKey":
+ return ThroughputKey(
+ country_code=test.country_code,
+ security_mode=test.security_mode,
+ channel_bandwidth=test.channel_bandwidth,
+ )
+
+
+@dataclass
+class ThroughputValue:
+ channel: int
+ tx_throughput_mbps: Optional[float]
+ rx_throughput_mbps: Optional[float]
+
+
+ChannelThroughputMap = Dict[ThroughputKey, List[ThroughputValue]]
class ChannelSweepTest(base_test.WifiBaseTest):
- """Tests channel performance and regulatory compliance..
+ """Tests channel performance.
Testbed Requirement:
- * One ACTS compatible device (dut)
- * One Access Point
- * One Linux Machine used as IPerfServer if running performance tests
+ * 1 x Fuchsia device (dut)
+ * 1 x access point
+ * 1 x Linux Machine used as IPerfServer
+
Note: Performance tests should be done in isolated testbed.
"""
- def __init__(self, controllers):
- super().__init__(controllers)
- if "channel_sweep_test_params" in self.user_params:
- self.time_to_wait_for_ip_addr = self.user_params[
- "channel_sweep_test_params"
- ].get("time_to_wait_for_ip_addr", DEFAULT_TIME_TO_WAIT_FOR_IP_ADDR)
- else:
- self.time_to_wait_for_ip_addr = DEFAULT_TIME_TO_WAIT_FOR_IP_ADDR
+ def __init__(self, configs: List[Any]) -> None:
+ super().__init__(configs)
+ self.channel_throughput: ChannelThroughputMap = {}
+
+ def pre_run(self):
+ tests: List[Tuple[TestParams]] = []
+
+ def generate_test_name(test: TestParams):
+ security = test.security_mode if test.security_mode else "open"
+ return f"test_{test.country_code}_{security}_channel_{test.channel}_{test.channel_bandwidth}mhz"
+
+ def test_params(test_name):
+ return self.user_params.get("channel_sweep_test_params", {}).get(
+ test_name, {}
+ )
+
+ for country_channels in [COUNTRY_CHANNELS["United States of America"]]:
+ for security_mode in [
+ None,
+ SecurityMode.WEP,
+ SecurityMode.WPA,
+ SecurityMode.WPA2,
+ SecurityMode.WPA_WPA2,
+ SecurityMode.WPA3,
+ ]:
+ for channel, bandwidths in country_channels.allowed_channels.items():
+ for bandwidth in bandwidths:
+ test = TestParams(
+ country_code=country_channels.country_code,
+ security_mode=security_mode,
+ channel=channel,
+ channel_bandwidth=bandwidth,
+ )
+ name = generate_test_name(test)
+ test.expect_min_rx_throughput_mbps = test_params(name).get(
+ "min_rx_throughput", DEFAULT_MIN_THROUGHPUT
+ )
+ test.expect_min_tx_throughput_mbps = test_params(name).get(
+ "min_tx_throughput", DEFAULT_MIN_THROUGHPUT
+ )
+ test.expect_max_std_dev = test_params(name).get(
+ "max_std_dev", DEFAULT_MAX_STD_DEV
+ )
+ tests.append((test,))
+
+ self.generate_tests(self.run_channel_performance, generate_test_name, tests)
+
+ def get_existing_test_names(self) -> List[str]:
+ test_names: List[str] = super().get_existing_test_names()
+ # Verify standard deviation last since it depends on the throughput results from
+ # all other tests.
+ test_names.sort(key=lambda n: n == "test_standard_deviation")
+ return test_names
def setup_class(self):
super().setup_class()
self.log = logging.getLogger()
+ self.time_to_wait_for_ip_addr = self.user_params.get(
+ "channel_sweep_test_params", {}
+ ).get("time_to_wait_for_ip_addr", DEFAULT_TIME_TO_WAIT_FOR_IP_ADDR)
+
device_type = self.user_params.get("dut", "fuchsia_devices")
if device_type == "fuchsia_devices":
self.fuchsia_device = self.fuchsia_devices[0]
@@ -108,40 +187,17 @@
self.access_point = self.access_points[0]
self.access_point.stop_all_aps()
- self.iperf_server = None
- self.iperf_client = None
+ self.iperf_server = self.iperf_servers[0]
+ self.iperf_server.start()
- self.channel_sweep_test_params = self.user_params.get(
- "channel_sweep_test_params", {}
- )
- # Allows users to skip the iperf throughput measurements, just verifying
- # association.
- if not self.channel_sweep_test_params.get("skip_performance"):
- try:
- self.iperf_server = self.iperf_servers[0]
- self.iperf_server.start()
- except AttributeError:
- self.log.warn(
- "Missing iperf config. Throughput cannot be measured, so only "
- "association will be tested."
- )
-
- if hasattr(self, "iperf_clients") and self.iperf_clients:
- self.iperf_client = self.iperf_clients[0]
- else:
- self.iperf_client = self.dut.create_iperf_client()
-
- self.regulatory_results = "====CountryCode,Channel,Frequency,ChannelBandwith,Connected/Not-Connected====\n"
+ if hasattr(self, "iperf_clients") and self.iperf_clients:
+ self.iperf_client = self.iperf_clients[0]
+ else:
+ self.iperf_client = self.dut.create_iperf_client()
def teardown_class(self):
+ self.write_graph()
super().teardown_class()
- output_path = context.get_current_context().get_base_output_path()
- regulatory_save_path = (
- f"{output_path}/ChannelSweepTest/{'regulatory_results.txt'}"
- )
- f = open(regulatory_save_path, "w")
- f.write(self.regulatory_results)
- f.close()
def setup_test(self):
super().setup_test()
@@ -177,92 +233,25 @@
self.access_point.stop_all_aps()
super().teardown_test()
- def set_dut_country_code(self, country_code):
- """Set the country code on the DUT. Then verify that the country
- code was set successfully
-
- Args:
- country_code: string, the 2 character country code to set
- """
- self.log.info(f"Setting DUT country code to {country_code}")
- country_code_response = (
- self.fuchsia_device.sl4f.regulatory_region_lib.setRegion(country_code)
- )
- if country_code_response.get("error"):
- raise EnvironmentError(
- f"Failed to set country code ({country_code}) on DUT. "
- f"Error: {country_code_response['error']}"
- )
-
- self.log.info(
- f"Verifying DUT country code was correctly set to {country_code}."
- )
- phy_ids = self.dut.get_wlan_interface_id_list()
-
- end_time = time.time() + TIME_TO_WAIT_FOR_COUNTRY_CODE
- while time.time() < end_time:
- for id in phy_ids:
- get_country_response = self.fuchsia_device.sl4f.wlan_lib.wlanGetCountry(
- id
- )
- if get_country_response.get("error"):
- raise ConnectionError(
- f"Failed to query PHY ID ({id}) for country. "
- f"Error: {get_country_response['error']}"
- )
-
- set_code = "".join(
- [chr(ascii_char) for ascii_char in get_country_response["result"]]
- )
- if set_code != country_code:
- self.log.debug(
- f"PHY (id: {id}) has incorrect country code set. "
- f"Expected: {country_code}, Got: {set_code}"
- )
- break
- else:
- self.log.info(f"All PHYs have expected country code ({country_code})")
- break
- time.sleep(TIME_TO_SLEEP_BETWEEN_RETRIES)
- else:
- raise EnvironmentError(f"Failed to set DUT country code to {country_code}.")
-
- def setup_ap(self, channel, channel_bandwidth, security_profile=None):
+ def setup_ap(
+ self,
+ channel: int,
+ channel_bandwidth: int,
+ security_profile: Optional[Security] = None,
+ ) -> str:
"""Start network on AP with basic configuration.
Args:
- channel: int, channel to use for network
- channel_bandwidth: int, channel bandwidth in mhz to use for network,
- security_profile: Security object, or None if open
+ channel: channel to use for network
+ channel_bandwidth: channel bandwidth in mhz to use for network,
+ security_profile: security type to use or None if open
Returns:
- string, ssid of network running
+ SSID of the newly created and running network
Raises:
ConnectionError if network is not started successfully.
"""
- if channel > MAX_2_4_CHANNEL:
- vht_bandwidth = channel_bandwidth
- else:
- vht_bandwidth = None
-
- if channel_bandwidth == hostapd_constants.CHANNEL_BANDWIDTH_20MHZ:
- n_capabilities = N_CAPABILITIES_DEFAULT + [
- hostapd_constants.N_CAPABILITY_HT20
- ]
- elif (
- channel_bandwidth == hostapd_constants.CHANNEL_BANDWIDTH_40MHZ
- or channel_bandwidth == hostapd_constants.CHANNEL_BANDWIDTH_80MHZ
- ):
- if hostapd_config.ht40_plus_allowed(channel):
- extended_channel = [hostapd_constants.N_CAPABILITY_HT40_PLUS]
- elif hostapd_config.ht40_minus_allowed(channel):
- extended_channel = [hostapd_constants.N_CAPABILITY_HT40_MINUS]
- else:
- raise ValueError(f"Invalid Channel: {channel}")
- n_capabilities = N_CAPABILITIES_DEFAULT + extended_channel
- else:
- raise ValueError(f"Invalid Bandwidth: {channel_bandwidth}")
ssid = utils.rand_ascii_str(hostapd_constants.AP_SSID_LENGTH_2G)
try:
setup_ap(
@@ -270,25 +259,21 @@
profile_name="whirlwind",
channel=channel,
security=security_profile,
- n_capabilities=n_capabilities,
- ac_capabilities=None,
force_wmm=True,
ssid=ssid,
- vht_bandwidth=vht_bandwidth,
+ vht_bandwidth=channel_bandwidth,
setup_bridge=True,
)
+ self.log.info(
+ f"Network (ssid: {ssid}) up on channel {channel} "
+ f"w/ channel bandwidth {channel_bandwidth} MHz"
+ )
+ return ssid
except Exception as err:
raise ConnectionError(
f"Failed to setup ap on channel: {channel}, "
- f"channel bandwidth: {channel_bandwidth}mhz. Error: {err}"
- )
- else:
- self.log.info(
- f"Network (ssid: {ssid}) up on channel {channel} w/ "
- f"channel bandwidth {channel_bandwidth}mhz"
- )
-
- return ssid
+ f"channel bandwidth: {channel_bandwidth} MHz. "
+ ) from err
def get_and_verify_iperf_address(self, channel, device, interface=None):
"""Get ip address from a devices interface and verify it belongs to
@@ -334,18 +319,20 @@
raise ConnectionError("Device failed to get an ip address.")
def get_iperf_throughput(
- self, iperf_server_address, iperf_client_address, reverse=False
- ):
+ self,
+ iperf_server_address: str,
+ iperf_client_address: str,
+ reverse: bool = False,
+ ) -> float:
"""Run iperf between client and server and get the throughput.
Args:
- iperf_server_address: string, ip address of running iperf server
- iperf_client_address: string, ip address of iperf client (dut)
- reverse (default: False): If True, run traffic in reverse direction,
- from server to client.
+ iperf_server_address: IP address of running iperf server
+ iperf_client_address: IP address of iperf client (dut)
+ reverse: If True, run traffic in reverse direction, from server to client.
Returns:
- int, iperf throughput OR IPERF_NO_THROUGHPUT_VALUE, if iperf fails
+ iperf throughput or 0 if iperf fails
"""
if reverse:
self.log.info(
@@ -373,12 +360,14 @@
iperf_results = IPerfResult(
iperf_results_file, reporting_speed_units=MEGABITS_PER_SECOND
)
- return iperf_results.avg_send_rate
- else:
- return IPERF_NO_THROUGHPUT_VALUE
+ return iperf_results.avg_send_rate or 0.0
+ return 0.0
def log_to_file_and_throughput_data(
- self, channel, channel_bandwidth, tx_throughput, rx_throughput
+ self,
+ test: TestParams,
+ tx_throughput: Optional[float],
+ rx_throughput: Optional[float],
):
"""Write performance info to csv file and to throughput data.
@@ -388,19 +377,32 @@
tx_throughput: float, throughput value from dut to iperf server
rx_throughput: float, throughput value from iperf server to dut
"""
- test_name = self.throughput_data["test"]
- output_path = context.get_current_context().get_base_output_path()
- log_path = f"{output_path}/ChannelSweepTest/{test_name}"
- if not os.path.exists(log_path):
- os.makedirs(log_path)
- log_file = f"{log_path}/{test_name}_{channel_bandwidth}mhz.csv"
+ test_name = self.current_test_info.name
+ log_file = Path(os.path.join(self.log_path, "throughput.csv"))
self.log.info(f"Writing IPerf results for {test_name} to {log_file}")
+
+ if not log_file.is_file():
+ with open(log_file, "x") as csv_file:
+ csv_file.write(
+ "country code,security,channel,channel bandwidth,tx throughput,rx throughput\n"
+ )
+
with open(log_file, "a") as csv_file:
- csv_file.write(f"{channel},{tx_throughput},{rx_throughput}\n")
- self.throughput_data["results"][str(channel)] = {
- "tx_throughput": tx_throughput,
- "rx_throughput": rx_throughput,
- }
+ csv_file.write(
+ f"{test.country_code},{test.security_mode},{test.channel},{test.channel_bandwidth},{tx_throughput},{rx_throughput}\n"
+ )
+
+ key = ThroughputKey.from_test(test)
+ if key not in self.channel_throughput:
+ self.channel_throughput[key] = []
+
+ self.channel_throughput[key].append(
+ ThroughputValue(
+ channel=test.channel,
+ tx_throughput_mbps=tx_throughput,
+ rx_throughput_mbps=rx_throughput,
+ )
+ )
def write_graph(self):
"""Create graph html files from throughput data, plotting channel vs
@@ -411,7 +413,12 @@
return
try:
- from bokeh.plotting import ColumnDataSource, figure, output_file, save
+ from bokeh.plotting import ( # type: ignore
+ ColumnDataSource,
+ figure,
+ output_file,
+ save,
+ )
except ImportError:
self.log.warn(
"bokeh is not installed: skipping creation of graphs. "
@@ -420,90 +427,86 @@
)
return
- output_path = context.get_current_context().get_base_output_path()
- test_name = self.throughput_data["test"]
- channel_bandwidth = self.throughput_data["channel_bandwidth"]
- output_file_name = os.path.join(
- output_path,
- "ChannelSweepTest",
- test_name,
- f"{test_name}_{channel_bandwidth}mhz.html",
- )
- output_file(output_file_name)
- channels = []
- tx_throughputs = []
- rx_throughputs = []
- for channel in self.throughput_data["results"]:
- channels.append(str(channel))
- tx_throughputs.append(
- self.throughput_data["results"][channel]["tx_throughput"]
+ for key in self.channel_throughput.keys():
+ output_file_name = os.path.join(
+ self.log_path,
+ f"channel_throughput_{key.country_code}_{key.security_mode}_{key.channel_bandwidth}mhz.html",
)
- rx_throughputs.append(
- self.throughput_data["results"][channel]["rx_throughput"]
+ output_file(output_file_name)
+ channels = []
+ tx_throughputs = []
+ rx_throughputs = []
+
+ for throughput in sorted(
+ self.channel_throughput[key], key=lambda t: t.channel
+ ):
+ channels.append(str(throughput.channel))
+ tx_throughputs.append(throughput.tx_throughput_mbps)
+ rx_throughputs.append(throughput.rx_throughput_mbps)
+
+ channel_vs_throughput_data = ColumnDataSource(
+ data=dict(
+ channels=channels,
+ tx_throughput=tx_throughputs,
+ rx_throughput=rx_throughputs,
+ )
)
- channel_vs_throughput_data = ColumnDataSource(
- data=dict(
- channels=channels,
- tx_throughput=tx_throughputs,
- rx_throughput=rx_throughputs,
+ TOOLTIPS = [
+ ("Channel", "@channels"),
+ ("TX_Throughput", "@tx_throughput"),
+ ("RX_Throughput", "@rx_throughput"),
+ ]
+ channel_vs_throughput_graph = figure(
+ title="Channels vs. Throughput",
+ x_axis_label="Channels",
+ x_range=channels,
+ y_axis_label="Throughput",
+ tooltips=TOOLTIPS,
)
- )
- TOOLTIPS = [
- ("Channel", "@channels"),
- ("TX_Throughput", "@tx_throughput"),
- ("RX_Throughput", "@rx_throughput"),
- ]
- channel_vs_throughput_graph = figure(
- title="Channels vs. Throughput",
- x_axis_label="Channels",
- x_range=channels,
- y_axis_label="Throughput",
- tooltips=TOOLTIPS,
- )
- channel_vs_throughput_graph.sizing_mode = "stretch_both"
- channel_vs_throughput_graph.title.align = "center"
- channel_vs_throughput_graph.line(
- "channels",
- "tx_throughput",
- source=channel_vs_throughput_data,
- line_width=2,
- line_color="blue",
- legend_label="TX_Throughput",
- )
- channel_vs_throughput_graph.circle(
- "channels",
- "tx_throughput",
- source=channel_vs_throughput_data,
- size=GRAPH_CIRCLE_SIZE,
- color="blue",
- )
- channel_vs_throughput_graph.line(
- "channels",
- "rx_throughput",
- source=channel_vs_throughput_data,
- line_width=2,
- line_color="red",
- legend_label="RX_Throughput",
- )
- channel_vs_throughput_graph.circle(
- "channels",
- "rx_throughput",
- source=channel_vs_throughput_data,
- size=GRAPH_CIRCLE_SIZE,
- color="red",
- )
+ channel_vs_throughput_graph.sizing_mode = "stretch_both"
+ channel_vs_throughput_graph.title.align = "center"
+ channel_vs_throughput_graph.line(
+ "channels",
+ "tx_throughput",
+ source=channel_vs_throughput_data,
+ line_width=2,
+ line_color="blue",
+ legend_label="TX_Throughput",
+ )
+ channel_vs_throughput_graph.circle(
+ "channels",
+ "tx_throughput",
+ source=channel_vs_throughput_data,
+ size=GRAPH_CIRCLE_SIZE,
+ color="blue",
+ )
+ channel_vs_throughput_graph.line(
+ "channels",
+ "rx_throughput",
+ source=channel_vs_throughput_data,
+ line_width=2,
+ line_color="red",
+ legend_label="RX_Throughput",
+ )
+ channel_vs_throughput_graph.circle(
+ "channels",
+ "rx_throughput",
+ source=channel_vs_throughput_data,
+ size=GRAPH_CIRCLE_SIZE,
+ color="red",
+ )
- channel_vs_throughput_graph.legend.location = "top_left"
- graph_file = save([channel_vs_throughput_graph])
- self.log.info(f"Saved graph to {graph_file}")
+ channel_vs_throughput_graph.legend.location = "top_left"
+ graph_file = save([channel_vs_throughput_graph])
+ self.log.info(f"Saved graph to {graph_file}")
- def verify_standard_deviation(self, max_std_dev):
- """Verifies the standard deviation of the throughput across the channels
- does not exceed the max_std_dev value.
+ def test_standard_deviation(self):
+ """Verify throughputs don't deviate too much across channels.
- Args:
- max_std_dev: float, max standard deviation of throughput for a test
- to pass (in Mb/s)
+ Assert the throughput standard deviation across all channels of the same
+ country, security, and bandwidth does not exceed the maximum specified in the
+ user param config. If no maximum is set, a default of 1.0 standard deviations
+ will be used (34.1% from the mean).
Raises:
TestFailure, if standard deviation of throughput exceeds max_std_dev
@@ -511,143 +514,53 @@
# If performance measurement is skipped
if not self.iperf_server:
return
+
+ max_std_dev = self.user_params.get("channel_sweep_test_params", {}).get(
+ "max_std_dev", DEFAULT_MAX_STD_DEV
+ )
+
self.log.info(
"Verifying standard deviation across channels does not exceed max standard "
f"deviation of {max_std_dev} Mb/s"
)
- tx_values = []
- rx_values = []
- for channel in self.throughput_data["results"]:
- if self.throughput_data["results"][channel]["tx_throughput"] is not None:
- tx_values.append(
- self.throughput_data["results"][channel]["tx_throughput"]
+
+ errors: List[str] = []
+
+ for test, throughputs in self.channel_throughput.items():
+ tx_values = []
+ rx_values = []
+ for throughput in throughputs:
+ if throughput.tx_throughput_mbps is not None:
+ tx_values.append(throughput.tx_throughput_mbps)
+ if throughput.rx_throughput_mbps is not None:
+ rx_values.append(throughput.rx_throughput_mbps)
+
+ tx_std_dev = pstdev(tx_values)
+ rx_std_dev = pstdev(rx_values)
+
+ if tx_std_dev > max_std_dev:
+ errors.append(
+ f"[{test.country_code} {test.security_mode} "
+ f"{test.channel_bandwidth}mhz] TX throughput standard deviation "
+ f"{tx_std_dev} Mb/s exceeds expected max of {max_std_dev} Mb/s"
)
- if self.throughput_data["results"][channel]["rx_throughput"] is not None:
- rx_values.append(
- self.throughput_data["results"][channel]["rx_throughput"]
+ if rx_std_dev > max_std_dev:
+ errors.append(
+ f"[{test.country_code} {test.security_mode} "
+ f"{test.channel_bandwidth}mhz] RX throughput standard deviation "
+ f"{rx_std_dev} Mb/s exceeds expected max of {max_std_dev} Mb/s"
)
- tx_std_dev = pstdev(tx_values)
- rx_std_dev = pstdev(rx_values)
- if tx_std_dev > max_std_dev or rx_std_dev > max_std_dev:
+
+ if errors:
+ error_message = "\n - ".join(errors)
asserts.fail(
- f"With {self.throughput_data['channel_bandwidth']}mhz channel "
- f"bandwidth, throughput standard deviation (tx: {tx_std_dev} Mb/s, "
- f"rx: {rx_std_dev} Mb/s) exceeds max standard deviation "
- f"({max_std_dev} Mb/s)."
- )
- else:
- bandwidth = self.throughput_data["channel_bandwidth"]
- asserts.explicit_pass(
- f"Throughput standard deviation (tx: {tx_std_dev} Mb/s, "
- f"rx: {rx_std_dev} Mb/s) with {bandwidth}mhz channel bandwidth does "
- f"not exceed maximum ({max_std_dev} Mb/s)."
+ f"Failed to meet standard deviation expectations:\n - {error_message}"
)
- def run_channel_performance_tests(self, settings):
- """Test function for running channel performance tests. Used by both
- explicit test cases and debug test cases from config. Runs a performance
- test for each channel in test_channels with test_channel_bandwidth, then
- writes a graph and csv file of the channel vs throughput.
+ def run_channel_performance(self, test: TestParams):
+ """Run a single channel performance test
- Args:
- settings: dict, containing the following test settings
- test_channels: list of channels to test.
- test_channel_bandwidth: int, channel bandwidth to use for test.
- test_security (optional): string, security type to use for test.
- min_tx_throughput (optional, default: 0): float, minimum tx
- throughput threshold to pass individual channel tests
- (in Mb/s).
- min_rx_throughput (optional, default: 0): float, minimum rx
- throughput threshold to pass individual channel tests
- (in Mb/s).
- max_std_dev (optional, default: 1): float, maximum standard
- deviation of throughput across all test channels to pass
- test (in Mb/s).
- base_test_name (optional): string, test name prefix to use with
- generated subtests.
- country_name (optional): string, country name from
- hostapd_constants to set on device.
- country_code (optional): string, two-char country code to set on
- the DUT. Takes priority over country_name.
- test_name (debug tests only): string, the test name for this
- parent test case from the config file. In explicit tests,
- this is not necessary.
-
- Writes:
- CSV file: channel, tx_throughput, rx_throughput
- for every test channel.
- Graph: channel vs tx_throughput & channel vs rx_throughput
-
- Raises:
- TestFailure, if throughput standard deviation across channels
- exceeds max_std_dev
-
- Example Explicit Test (see EOF for debug JSON example):
- def test_us_2g_20mhz_wpa2(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G,
- test_channel_bandwidth=20,
- test_security=hostapd_constants.WPA2_STRING,
- min_tx_throughput=2,
- min_rx_throughput=4,
- max_std_dev=0.75,
- country_code='US',
- base_test_name='test_us'))
- """
- test_channels = settings["test_channels"]
- test_channel_bandwidth = settings["test_channel_bandwidth"]
- test_security = settings.get("test_security", None)
- test_name = settings.get("test_name", self.test_name)
- min_tx_throughput = settings.get("min_tx_throughput", DEFAULT_MIN_THROUGHPUT)
- min_rx_throughput = settings.get("min_rx_throughput", DEFAULT_MIN_THROUGHPUT)
- max_std_dev = settings.get("max_std_dev", DEFAULT_MAX_STD_DEV)
- country_code = settings.get("country_code")
- country_name = settings.get("country_name")
- country_label = None
-
- if country_code:
- country_label = country_code
- self.set_dut_country_code(country_code)
- elif country_name:
- country_label = country_name
- code = hostapd_constants.COUNTRY_CODE[country_name]["country_code"]
- self.set_dut_country_code(code)
-
- self.throughput_data = {
- "test": test_name,
- "channel_bandwidth": test_channel_bandwidth,
- "results": {},
- }
- test_list = []
- for channel in test_channels:
- sub_test_name = "test_%schannel_%s_%smhz_%s_performance" % (
- "%s_" % country_label if country_label else "",
- channel,
- test_channel_bandwidth,
- test_security if test_security else "open",
- )
- test_list.append(
- {
- "test_name": sub_test_name,
- "channel": int(channel),
- "channel_bandwidth": int(test_channel_bandwidth),
- "security": test_security,
- "min_tx_throughput": min_tx_throughput,
- "min_rx_throughput": min_rx_throughput,
- }
- )
- self.run_generated_testcases(
- self.get_channel_performance, settings=test_list, name_func=get_test_name
- )
- self.log.info("Channel tests completed.")
- self.write_graph()
- self.verify_standard_deviation(max_std_dev)
-
- def get_channel_performance(self, settings):
- """Run a single channel performance test and logs results to csv file
- and throughput data. Run with generated sub test cases in
- run_channel_performance_tests.
+ Log results to csv file and throughput data.
1. Sets up network with test settings
2. Associates DUT
@@ -656,43 +569,34 @@
log file and throughput data.
5. Checks throughput values against minimum throughput thresholds.
- Args:
- settings: see run_channel_performance_tests
-
Raises:
TestFailure, if throughput (either direction) is less than
the directions given minimum throughput threshold.
"""
- channel = settings["channel"]
- channel_bandwidth = settings["channel_bandwidth"]
- security = settings["security"]
- min_tx_throughput = settings["min_tx_throughput"]
- min_rx_throughput = settings["min_rx_throughput"]
- if security:
- if security == hostapd_constants.WEP_STRING:
+ self.fuchsia_device.wlan_policy_controller.set_country_code(test.country_code)
+
+ if test.security_mode:
+ if test.security_mode == SecurityMode.WEP:
password = utils.rand_hex_str(WEP_HEX_STRING_LENGTH)
else:
password = utils.rand_ascii_str(hostapd_constants.MIN_WPA_PSK_LENGTH)
- security_profile = Security(security_mode=security, password=password)
- target_security = (
- hostapd_constants.SECURITY_STRING_TO_DEFAULT_TARGET_SECURITY.get(
- security
- )
+ security_profile = Security(
+ security_mode=test.security_mode, password=password
)
+ target_security = test.security_mode.default_target_security()
else:
password = None
security_profile = None
target_security = None
- ssid = self.setup_ap(channel, channel_bandwidth, security_profile)
+
+ ssid = self.setup_ap(test.channel, test.channel_bandwidth, security_profile)
associated = self.dut.associate(
ssid, target_pwd=password, target_security=target_security
)
if not associated:
if self.iperf_server:
- self.log_to_file_and_throughput_data(
- channel, channel_bandwidth, None, None
- )
- asserts.fail(f"Device failed to associate with network {ssid}")
+ self.log_to_file_and_throughput_data(test, None, None)
+ asserts.fail(f"Device failed to associate to network {ssid}")
self.log.info(f"DUT ({self.dut.identifier}) connected to network {ssid}.")
if self.iperf_server:
self.iperf_server.renew_test_interface_ip_address()
@@ -701,14 +605,18 @@
f"{self.time_to_wait_for_ip_addr} seconds."
)
iperf_server_address = self.get_and_verify_iperf_address(
- channel, self.iperf_server
+ test.channel, self.iperf_server
)
self.log.info(
"Getting ip address for DUT. Will retry for "
f"{self.time_to_wait_for_ip_addr} seconds."
)
+
+ assert isinstance(
+ self.iperf_client, (IPerfClientOverSsh, IPerfClientOverAdb)
+ )
iperf_client_address = self.get_and_verify_iperf_address(
- channel, self.fuchsia_device, self.iperf_client.test_interface
+ test.channel, self.fuchsia_device, self.iperf_client.test_interface
)
tx_throughput = self.get_iperf_throughput(
iperf_server_address, iperf_client_address
@@ -716,504 +624,24 @@
rx_throughput = self.get_iperf_throughput(
iperf_server_address, iperf_client_address, reverse=True
)
- self.log_to_file_and_throughput_data(
- channel, channel_bandwidth, tx_throughput, rx_throughput
- )
+ self.log_to_file_and_throughput_data(test, tx_throughput, rx_throughput)
self.log.info(
f"Throughput (tx, rx): ({tx_throughput} Mb/s, {rx_throughput} Mb/s), "
- f"Minimum threshold (tx, rx): ({min_tx_throughput} Mb/s, "
- f"{min_rx_throughput} Mb/s)"
+ "Minimum threshold (tx, rx): "
+ f"({test.expect_min_tx_throughput_mbps} Mb/s, "
+ f"{test.expect_min_rx_throughput_mbps} Mb/s)"
)
- base_message = (
- f"Actual throughput (on channel: {channel}, "
- f"channel bandwidth: {channel_bandwidth}, security: {security})"
+ asserts.assert_less(
+ tx_throughput,
+ test.expect_min_tx_throughput_mbps,
+ "tx throughput below the minimal threshold",
)
- if (
- not tx_throughput
- or not rx_throughput
- or tx_throughput < min_tx_throughput
- or rx_throughput < min_rx_throughput
- ):
- asserts.fail(f"{base_message} below the minimum threshold.")
- asserts.explicit_pass(f"{base_message} above the minimum threshold.")
- else:
- asserts.explicit_pass(
- "Association test pass. No throughput measurement taken."
+ asserts.assert_less(
+ rx_throughput,
+ test.expect_min_rx_throughput_mbps,
+ "rx throughput below the minimal threshold",
)
- def verify_regulatory_compliance(self, settings):
- """Test function for regulatory compliance tests. Verify device complies
- with provided regulatory requirements.
-
- Args:
- settings: dict, containing the following test settings
- test_channels: dict, mapping channels to a set of the channel
- bandwidths to test (see example for using JSON). Defaults
- to hostapd_constants.ALL_CHANNELS.
- country_code: string, two-char country code to set on device
- (prioritized over country_name)
- country_name: string, country name from hostapd_constants to set
- on device.
- base_test_name (optional): string, test name prefix to use with
- generatedsubtests.
- test_name: string, the test name for this
- parent test case from the config file. In explicit tests,
- this is not necessary.
- """
- country_name = settings.get("country_name")
- country_code = settings.get("country_code")
- if not (country_code or country_name):
- raise ValueError("No country code or name provided.")
-
- test_channels = settings.get("test_channels", hostapd_constants.ALL_CHANNELS)
- allowed_channels = settings["allowed_channels"]
-
- base_test_name = settings.get("base_test_name", "test_compliance")
-
- if country_code:
- code = country_code
- else:
- code = hostapd_constants.COUNTRY_CODE[country_name]["country_code"]
-
- self.set_dut_country_code(code)
-
- test_list = []
- for channel in test_channels:
- for channel_bandwidth in test_channels[channel]:
- sub_test_name = (
- f"{base_test_name}_channel_{channel}_{channel_bandwidth}mhz"
- )
- should_associate = (
- channel in allowed_channels
- and channel_bandwidth in allowed_channels[channel]
- )
- # Note: these int conversions because when these tests are
- # imported via JSON, they may be strings since the channels
- # will be keys. This makes the json/list test_channels param
- # behave exactly like the in code dict/set test_channels.
- test_list.append(
- {
- "country_code": code,
- "channel": int(channel),
- "channel_bandwidth": int(channel_bandwidth),
- "should_associate": should_associate,
- "test_name": sub_test_name,
- }
- )
- self.run_generated_testcases(
- test_func=self.verify_channel_compliance,
- settings=test_list,
- name_func=get_test_name,
- )
-
- def verify_channel_compliance(self, settings):
- """Verify device complies with provided regulatory requirements for a
- specific channel and channel bandwidth. Run with generated test cases
- in the verify_regulatory_compliance parent test.
- _
- Args:
- settings: see verify_regulatory_compliance`
- """
- channel = settings["channel"]
- channel_bandwidth = settings["channel_bandwidth"]
- code = settings["country_code"]
- should_associate = settings["should_associate"]
-
- ssid = self.setup_ap(channel, channel_bandwidth)
-
- self.log.info(
- f"Attempting to associate with network ({ssid}) on channel {channel} "
- f"@ {channel_bandwidth}mhz. Expected behavior: "
- + (
- "Device should associate"
- if should_associate
- else "Device should NOT associate."
- )
- )
-
- associated = self.dut.associate(ssid)
-
- regulatory_result_marker = (
- f"REGTRACKER: {code},{channel},{'2.4' if channel < 36 else '5'},"
- f"{channel_bandwidth},{'c' if associated else 'nc'}"
- )
- self.regulatory_results += regulatory_result_marker + "\n"
- self.log.info(regulatory_result_marker)
-
- if associated == should_associate:
- asserts.explicit_pass(
- f"Device complied with {code} regulatory requirement for "
- f"channel {channel} with channel bandwidth {channel_bandwidth}mhz. "
- + ("Associated." if associated else "Refused to associate.")
- )
- else:
- asserts.fail(
- f"Device failed compliance with regulatory domain {code} for "
- f"channel {channel} with channel bandwidth {channel_bandwidth}mhz. "
- f"Expected: Should {'' if should_associate else 'not '}associate, "
- f"Got: {'Associated' if associated else 'Did not associate'}"
- )
-
- # Helper functions to allow explicit tests throughput and standard deviation
- # thresholds to be passed in via config.
- def _get_min_tx_throughput(self, test_name):
- return (
- self.user_params.get("channel_sweep_test_params", {})
- .get(test_name, {})
- .get("min_tx_throughput", DEFAULT_MIN_THROUGHPUT)
- )
-
- def _get_min_rx_throughput(self, test_name):
- return (
- self.user_params.get("channel_sweep_test_params", {})
- .get(test_name, {})
- .get("min_rx_throughput", DEFAULT_MIN_THROUGHPUT)
- )
-
- def _get_max_std_dev(self, test_name):
- return (
- self.user_params.get("channel_sweep_test_params", {})
- .get(test_name, {})
- .get("min_std_dev", DEFAULT_MAX_STD_DEV)
- )
-
- # Channel Performance of US Channels: 570 Test Cases
- # 36 Test Cases
- def test_us_20mhz_open_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G,
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_20MHZ,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 35 Test Cases
- def test_us_40mhz_open_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_40MHZ,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 24 Test Cases
- def test_us_80mhz_open_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_80MHZ,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 36 Test Cases
- def test_us_20mhz_wep_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G,
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_20MHZ,
- test_security=hostapd_constants.WEP_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 35 Test Cases
- def test_us_40mhz_wep_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_40MHZ,
- test_security=hostapd_constants.WEP_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 24 Test Cases
- def test_us_80mhz_wep_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_80MHZ,
- test_security=hostapd_constants.WEP_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 36 Test Cases
- def test_us_20mhz_wpa_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G,
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_20MHZ,
- test_security=hostapd_constants.WPA_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 35 Test Cases
- def test_us_40mhz_wpa_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_40MHZ,
- test_security=hostapd_constants.WPA_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 24 Test Cases
- def test_us_80mhz_wpa_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_80MHZ,
- test_security=hostapd_constants.WPA_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 36 Test Cases
- def test_us_20mhz_wpa2_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G,
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_20MHZ,
- test_security=hostapd_constants.WPA2_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 35 Test Cases
- def test_us_40mhz_wpa2_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_40MHZ,
- test_security=hostapd_constants.WPA2_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 24 Test Cases
- def test_us_80mhz_wpa2_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_80MHZ,
- test_security=hostapd_constants.WPA2_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 36 Test Cases
- def test_us_20mhz_wpa_wpa2_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G,
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_20MHZ,
- test_security=hostapd_constants.WPA_MIXED_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 35 Test Cases
- def test_us_40mhz_wpa_wpa2_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_40MHZ,
- test_security=hostapd_constants.WPA_MIXED_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 24 Test Cases
- def test_us_80mhz_wpa_wpa2_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_80MHZ,
- test_security=hostapd_constants.WPA_MIXED_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 36 Test Cases
- def test_us_20mhz_wpa3_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G,
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_20MHZ,
- test_security=hostapd_constants.WPA3_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 35 Test Cases
- def test_us_40mhz_wpa3_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_2G
- + hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_40MHZ,
- test_security=hostapd_constants.WPA3_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- # 24 Test Cases
- def test_us_80mhz_wpa3_channel_performance(self):
- self.run_channel_performance_tests(
- dict(
- test_channels=hostapd_constants.US_CHANNELS_5G[:-1],
- test_channel_bandwidth=hostapd_constants.CHANNEL_BANDWIDTH_80MHZ,
- test_security=hostapd_constants.WPA3_STRING,
- base_test_name=self.test_name,
- min_tx_throughput=self._get_min_tx_throughput(self.test_name),
- min_rx_throughput=self._get_min_rx_throughput(self.test_name),
- max_std_dev=self._get_max_std_dev(self.test_name),
- )
- )
-
- def test_channel_performance_debug(self):
- """Run channel performance test cases from the ACTS config file.
-
- Example:
- "channel_sweep_test_params": {
- "debug_channel_performance_tests": [
- {
- "test_name": "test_123_20mhz_wpa2_performance"
- "test_channels": [1, 2, 3],
- "test_channel_bandwidth": 20,
- "test_security": "wpa2",
- "base_test_name": "test_123_perf",
- "min_tx_throughput": 1.1,
- "min_rx_throughput": 3,
- "max_std_dev": 0.5
- },
- ...
- ]
- }
-
- """
- asserts.skip_if(
- "debug_channel_performance_tests"
- not in self.user_params.get("channel_sweep_test_params", {}),
- "No custom channel performance tests provided in config.",
- )
- base_tests = self.user_params["channel_sweep_test_params"][
- "debug_channel_performance_tests"
- ]
- self.run_generated_testcases(
- self.run_channel_performance_tests,
- settings=base_tests,
- name_func=get_test_name,
- )
-
- def test_regulatory_compliance(self):
- """Run regulatory compliance test case from the ACTS config file.
- Note: only one country_name OR country_code is required.
-
- Example:
- "channel_sweep_test_params": {
- "regulatory_compliance_tests": [
- {
- "test_name": "test_japan_compliance_1_13_36"
- "country_name": "JAPAN",
- "country_code": "JP",
- "test_channels": {
- "1": [20, 40], "13": [40], "36": [20, 40, 80]
- },
- "allowed_channels": {
- "1": [20, 40], "36": [20, 40, 80]
- },
- "base_test_name": "test_japan"
- },
- ...
- ]
- }
- """
- asserts.skip_if(
- "regulatory_compliance_tests"
- not in self.user_params.get("channel_sweep_test_params", {}),
- "No custom regulatory compliance tests provided in config.",
- )
-
- # TODO(http://b/280442689): Add "supported_country_codes" and
- # "unsupported_channels" to test params
- base_tests = self.user_params["channel_sweep_test_params"][
- "regulatory_compliance_tests"
- ]
- self.run_generated_testcases(
- self.verify_regulatory_compliance,
- settings=base_tests,
- name_func=get_test_name,
- )
-
if __name__ == "__main__":
test_runner.main()
diff --git a/tests/wlan/performance/channel_sweep_test_params.yaml b/tests/wlan/performance/channel_sweep_test_params.yaml
deleted file mode 100644
index b70490b..0000000
--- a/tests/wlan/performance/channel_sweep_test_params.yaml
+++ /dev/null
@@ -1,5408 +0,0 @@
-channel_sweep_test_params:
- skip_performance: false
- debug_channel_performance_tests:
- - test_name: test_random_2g_20mhz_channel
- test_channels:
- - 8
- test_channel_bandwidth: 20
- - test_name: test_random_dfs_5g_80mhz_channel
- test_channels:
- - 100
- test_channel_bandwidth: 80
- - test_name: test_random_nondfs_5g_80mhz_channel
- test_channels:
- - 157
- test_channel_bandwidth: 80
- - test_name: test_channel_165
- test_channels:
- - 165
- test_channel_bandwidth: 20
- regulatory_compliance_tests:
- - test_name: test_SE_regulatory_compliance
- country_code: SE
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_us_regulatory_compliance
- country_code: US
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_MX_regulatory_compliance
- country_code: MX
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_CA_regulatory_compliance
- country_code: CA
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_IN_regulatory_compliance
- country_code: IN
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_NZ_regulatory_compliance
- country_code: NZ
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_GB_regulatory_compliance
- country_code: GB
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_AU_regulatory_compliance
- country_code: AU
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_JP_regulatory_compliance
- country_code: JP
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- - test_name: test_FR_regulatory_compliance
- country_code: FR
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_DE_regulatory_compliance
- country_code: DE
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_CH_regulatory_compliance
- country_code: CH
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_BE_regulatory_compliance
- country_code: BE
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_IE_regulatory_compliance
- country_code: IE
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_NO_regulatory_compliance
- country_code: "NO"
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_ES_regulatory_compliance
- country_code: ES
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_IT_regulatory_compliance
- country_code: IT
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_NL_regulatory_compliance
- country_code: NL
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_DK_regulatory_compliance
- country_code: DK
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- - test_name: test_SG_regulatory_compliance
- country_code: SG
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_WW_regulatory_compliance
- country_code: WW
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- - test_name: test_TW_regulatory_compliance
- country_code: TW
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- - test_name: test_AT_regulatory_compliance
- country_code: AT
- test_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "14":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80
- "144":
- - 20
- - 40
- - 80
- "149":
- - 20
- - 40
- - 80
- "153":
- - 20
- - 40
- - 80
- "157":
- - 20
- - 40
- - 80
- "161":
- - 20
- - 40
- - 80
- "165":
- - 20
- allowed_channels:
- "1":
- - 20
- "2":
- - 20
- "3":
- - 20
- "4":
- - 20
- "5":
- - 20
- "6":
- - 20
- "7":
- - 20
- "8":
- - 20
- "9":
- - 20
- "10":
- - 20
- "11":
- - 20
- "12":
- - 20
- "13":
- - 20
- "36":
- - 20
- - 40
- - 80
- "40":
- - 20
- - 40
- - 80
- "44":
- - 20
- - 40
- - 80
- "48":
- - 20
- - 40
- - 80
- "52":
- - 20
- - 40
- - 80
- "56":
- - 20
- - 40
- - 80
- "60":
- - 20
- - 40
- - 80
- "64":
- - 20
- - 40
- - 80
- "100":
- - 20
- - 40
- - 80
- "104":
- - 20
- - 40
- - 80
- "108":
- - 20
- - 40
- - 80
- "112":
- - 20
- - 40
- - 80
- "116":
- - 20
- - 40
- - 80
- "120":
- - 20
- - 40
- - 80
- "124":
- - 20
- - 40
- - 80
- "128":
- - 20
- - 40
- - 80
- "132":
- - 20
- - 40
- - 80
- "136":
- - 20
- - 40
- - 80
- "140":
- - 20
- - 40
- - 80