/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.net.wifi; import static android.net.wifi.QosCharacteristics.DELIVERY_RATIO_95; import static android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_9999; import static junit.framework.Assert.assertFalse; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import android.os.Parcel; import org.junit.Test; public class QosCharacteristicsTest { private static final int TEST_MIN_SERVICE_INTERVAL_MICROS = 2000; private static final int TEST_MAX_SERVICE_INTERVAL_MICROS = 5000; private static final int TEST_MIN_DATA_RATE_KBPS = 500; private static final int TEST_BURST_SIZE_OCTETS = 2; private static final int TEST_DELAY_BOUND_MICROS = 200; private static final int TEST_MAX_MSDU_SIZE_OCTETS = 4; private static final int TEST_SERVICE_START_TIME_MICROS = 250; private static final int TEST_SERVICE_START_TIME_LINK_ID = 0x5; private static final int TEST_MEAN_DATA_RATE_KBPS = 1500; private static final int TEST_MSDU_LIFETIME_MILLIS = 400; private static final int TEST_DELIVERY_RATIO = QosCharacteristics.DELIVERY_RATIO_99; private static final int TEST_COUNT_EXPONENT = 5; /** * Get a Builder with the mandatory fields set to the default test values. */ private static QosCharacteristics.Builder getDefaultBuilder() { return new QosCharacteristics.Builder( TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, TEST_MIN_DATA_RATE_KBPS, TEST_DELAY_BOUND_MICROS); } /** * Get a QosCharacteristics with all fields set to the default test values. */ private static QosCharacteristics getDefaultQosCharacteristics() { return getDefaultBuilder() .setMaxMsduSizeOctets(TEST_MAX_MSDU_SIZE_OCTETS) .setServiceStartTimeInfo( TEST_SERVICE_START_TIME_MICROS, TEST_SERVICE_START_TIME_LINK_ID) .setMeanDataRateKbps(TEST_MEAN_DATA_RATE_KBPS) .setBurstSizeOctets(TEST_BURST_SIZE_OCTETS) .setMsduLifetimeMillis(TEST_MSDU_LIFETIME_MILLIS) .setMsduDeliveryInfo(TEST_DELIVERY_RATIO, TEST_COUNT_EXPONENT) .build(); } /** * Verify that all fields in the QosCharacteristics object contain the default test values. */ private static void validateDefaultFields(QosCharacteristics qosCharacteristics) { assertEquals(TEST_MIN_SERVICE_INTERVAL_MICROS, qosCharacteristics.getMinServiceIntervalMicros()); assertEquals(TEST_MAX_SERVICE_INTERVAL_MICROS, qosCharacteristics.getMaxServiceIntervalMicros()); assertEquals(TEST_MIN_DATA_RATE_KBPS, qosCharacteristics.getMinDataRateKbps()); assertEquals(TEST_DELAY_BOUND_MICROS, qosCharacteristics.getDelayBoundMicros()); assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MAX_MSDU_SIZE)); assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.SERVICE_START_TIME)); assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MEAN_DATA_RATE)); assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.BURST_SIZE)); assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MSDU_LIFETIME)); assertTrue(qosCharacteristics.containsOptionalField(QosCharacteristics.MSDU_DELIVERY_INFO)); assertEquals(TEST_MAX_MSDU_SIZE_OCTETS, qosCharacteristics.getMaxMsduSizeOctets()); assertEquals(TEST_SERVICE_START_TIME_MICROS, qosCharacteristics.getServiceStartTimeMicros()); assertEquals(TEST_SERVICE_START_TIME_LINK_ID, qosCharacteristics.getServiceStartTimeLinkId()); assertEquals(TEST_MEAN_DATA_RATE_KBPS, qosCharacteristics.getMeanDataRateKbps()); assertEquals(TEST_BURST_SIZE_OCTETS, qosCharacteristics.getBurstSizeOctets()); assertEquals(TEST_MSDU_LIFETIME_MILLIS, qosCharacteristics.getMsduLifetimeMillis()); assertEquals(TEST_DELIVERY_RATIO, qosCharacteristics.getDeliveryRatio()); assertEquals(TEST_COUNT_EXPONENT, qosCharacteristics.getCountExponent()); } /** * Test that the builder works correctly when provided valid values. */ @Test public void testBuilderValid() { QosCharacteristics qosCharacteristics = getDefaultQosCharacteristics(); validateDefaultFields(qosCharacteristics); } /** * Test that an exception is thrown if any of the mandatory fields are assigned an * invalid value. */ @Test public void testMandatoryFieldsInvalid() { // All mandatory fields must be positive. assertThrows(IllegalArgumentException.class, () -> new QosCharacteristics.Builder( 0, TEST_MAX_SERVICE_INTERVAL_MICROS, TEST_MIN_DATA_RATE_KBPS, TEST_DELAY_BOUND_MICROS).build()); assertThrows(IllegalArgumentException.class, () -> new QosCharacteristics.Builder( TEST_MIN_SERVICE_INTERVAL_MICROS, 0, TEST_MIN_DATA_RATE_KBPS, TEST_DELAY_BOUND_MICROS).build()); assertThrows(IllegalArgumentException.class, () -> new QosCharacteristics.Builder( TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, 0, TEST_DELAY_BOUND_MICROS).build()); assertThrows(IllegalArgumentException.class, () -> new QosCharacteristics.Builder( TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, TEST_MIN_DATA_RATE_KBPS, 0).build()); // Min service interval must be less than or equal to the max service interval. assertThrows(IllegalArgumentException.class, () -> new QosCharacteristics.Builder( 5000 /* minServiceInterval */, 3000 /* maxServiceInterval */, TEST_MIN_DATA_RATE_KBPS, 0).build()); } /** * Test that an exception is thrown if any optional values that expect a positive value * are assigned a zero value. */ @Test public void testOptionalFieldsInvalid_zeroValue() { assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().setMaxMsduSizeOctets(0).build()); assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().setMeanDataRateKbps(0).build()); assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().setBurstSizeOctets(0).build()); assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().setMsduLifetimeMillis(0).build()); } /** * Test that an exception is thrown if any optional values that expect a <32-bit value are * assigned a value that exceeds the expected bit size. */ @Test public void testOptionalFieldsInvalid_exceedUpperBound() { // Expects 16-bit value assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().setMaxMsduSizeOctets(0x1FFFF).build()); // Expects 16-bit value assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder().setMsduLifetimeMillis(0x1FFFF).build()); // Expects 4-bit link ID assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder() .setServiceStartTimeInfo(TEST_SERVICE_START_TIME_MICROS, 0x1F).build()); } /** * Test that an exception is thrown if any additional constraints on the optional fields * are broken. */ @Test public void testOptionalFieldsInvalid_additionalConstraints() { // MSDU lifetime should be >= the delay bound int delayBoundUs = 30_000; // 30 ms int msduLifetimeMs = 20; assertThrows(IllegalArgumentException.class, () -> new QosCharacteristics.Builder( TEST_MIN_SERVICE_INTERVAL_MICROS, TEST_MAX_SERVICE_INTERVAL_MICROS, TEST_MIN_DATA_RATE_KBPS, delayBoundUs) .setMsduLifetimeMillis(msduLifetimeMs) .build()); // MSDU delivery ratio should be a valid enum assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder() .setMsduDeliveryInfo(DELIVERY_RATIO_95 - 1, TEST_COUNT_EXPONENT) .build()); assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder() .setMsduDeliveryInfo(DELIVERY_RATIO_99_9999 + 1, TEST_COUNT_EXPONENT) .build()); // MSDU count exponent should be between 0 and 15 (inclusive) assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder() .setMsduDeliveryInfo(TEST_DELIVERY_RATIO, -1) .build()); assertThrows(IllegalArgumentException.class, () -> getDefaultBuilder() .setMsduDeliveryInfo(TEST_DELIVERY_RATIO, 16) .build()); } /** * Test that an exception is thrown if the caller attempts to get an optional field * that was not assigned a value. */ @Test public void testOptionalFields_unsetException() { assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getMaxMsduSizeOctets()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getServiceStartTimeMicros()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getServiceStartTimeLinkId()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getMeanDataRateKbps()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getBurstSizeOctets()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getMsduLifetimeMillis()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getDeliveryRatio()); assertThrows(IllegalStateException.class, () -> getDefaultBuilder().build().getCountExponent()); } /** * Tests that the parceling logic can properly read and write from a Parcel. */ @Test public void testParcelReadWrite() { QosCharacteristics qosCharacteristics = getDefaultQosCharacteristics(); Parcel parcel = Parcel.obtain(); qosCharacteristics.writeToParcel(parcel, 0); parcel.setDataPosition(0); // Rewind data position back to the beginning for read. QosCharacteristics unparceledQosCharacteristics = QosCharacteristics.CREATOR.createFromParcel(parcel); validateDefaultFields(unparceledQosCharacteristics); } /** * Tests that the overridden equality and hashCode operators properly compare the same object. */ @Test public void testSameObjectComparison() { QosCharacteristics qosCharacteristics1 = getDefaultQosCharacteristics(); QosCharacteristics qosCharacteristics2 = getDefaultQosCharacteristics(); assertTrue(qosCharacteristics1.equals(qosCharacteristics2)); assertEquals(qosCharacteristics1.hashCode(), qosCharacteristics2.hashCode()); } /** * Tests that the overridden equality and hashCode operators properly compare different objects. */ @Test public void testDifferentObjectComparison() { QosCharacteristics qosCharacteristics1 = getDefaultQosCharacteristics(); QosCharacteristics qosCharacteristics2 = getDefaultBuilder().build(); assertFalse(qosCharacteristics1.equals(qosCharacteristics2)); assertNotEquals(qosCharacteristics1.hashCode(), qosCharacteristics2.hashCode()); } }