1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.thread; 18 19 import static com.google.common.io.BaseEncoding.base16; 20 import static com.google.common.truth.Truth.assertThat; 21 22 import static org.junit.Assert.assertThrows; 23 24 import android.net.thread.ActiveOperationalDataset.Builder; 25 import android.net.thread.ActiveOperationalDataset.SecurityPolicy; 26 import android.util.SparseArray; 27 28 import androidx.test.ext.junit.runners.AndroidJUnit4; 29 import androidx.test.filters.SmallTest; 30 31 import com.google.common.primitives.Bytes; 32 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.mockito.MockitoAnnotations; 37 38 /** Unit tests for {@link ActiveOperationalDataset}. */ 39 @SmallTest 40 @RunWith(AndroidJUnit4.class) 41 public class ActiveOperationalDatasetTest { 42 // A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset new": 43 // Active Timestamp: 1 44 // Channel: 19 45 // Channel Mask: 0x07FFF800 46 // Ext PAN ID: ACC214689BC40BDF 47 // Mesh Local Prefix: fd64:db12:25f4:7e0b::/64 48 // Network Key: F26B3153760F519A63BAFDDFFC80D2AF 49 // Network Name: OpenThread-d9a0 50 // PAN ID: 0xD9A0 51 // PSKc: A245479C836D551B9CA557F7B9D351B4 52 // Security Policy: 672 onrcb 53 private static final byte[] VALID_DATASET_TLVS = 54 base16().decode( 55 "0E080000000000010000000300001335060004001FFFE002" 56 + "08ACC214689BC40BDF0708FD64DB1225F47E0B0510F26B31" 57 + "53760F519A63BAFDDFFC80D2AF030F4F70656E5468726561" 58 + "642D643961300102D9A00410A245479C836D551B9CA557F7" 59 + "B9D351B40C0402A0FFF8"); 60 61 @Before setUp()62 public void setUp() { 63 MockitoAnnotations.initMocks(this); 64 } 65 addTlv(byte[] dataset, String tlvHex)66 private static byte[] addTlv(byte[] dataset, String tlvHex) { 67 return Bytes.concat(dataset, base16().decode(tlvHex)); 68 } 69 70 @Test fromThreadTlvs_containsUnknownTlvs_unknownTlvsRetained()71 public void fromThreadTlvs_containsUnknownTlvs_unknownTlvsRetained() { 72 byte[] datasetWithUnknownTlvs = addTlv(VALID_DATASET_TLVS, "AA01FFBB020102"); 73 74 ActiveOperationalDataset dataset1 = 75 ActiveOperationalDataset.fromThreadTlvs(datasetWithUnknownTlvs); 76 ActiveOperationalDataset dataset2 = 77 ActiveOperationalDataset.fromThreadTlvs(dataset1.toThreadTlvs()); 78 79 SparseArray<byte[]> unknownTlvs = dataset2.getUnknownTlvs(); 80 assertThat(unknownTlvs.size()).isEqualTo(2); 81 assertThat(unknownTlvs.get(0xAA)).isEqualTo(new byte[] {(byte) 0xFF}); 82 assertThat(unknownTlvs.get(0xBB)).isEqualTo(new byte[] {0x01, 0x02}); 83 assertThat(dataset2).isEqualTo(dataset1); 84 } 85 86 @Test builder_buildWithTooLongTlvs_throwsIllegalState()87 public void builder_buildWithTooLongTlvs_throwsIllegalState() { 88 Builder builder = new Builder(ActiveOperationalDataset.fromThreadTlvs(VALID_DATASET_TLVS)); 89 for (int i = 0; i < 10; i++) { 90 builder.addUnknownTlv(i, new byte[20]); 91 } 92 93 assertThrows(IllegalStateException.class, () -> new Builder().build()); 94 } 95 96 @Test builder_setUnknownTlvs_success()97 public void builder_setUnknownTlvs_success() { 98 ActiveOperationalDataset dataset1 = 99 ActiveOperationalDataset.fromThreadTlvs(VALID_DATASET_TLVS); 100 SparseArray<byte[]> unknownTlvs = new SparseArray<>(2); 101 unknownTlvs.put(0x33, new byte[] {1, 2, 3}); 102 unknownTlvs.put(0x44, new byte[] {1, 2, 3, 4}); 103 104 ActiveOperationalDataset dataset2 = 105 new ActiveOperationalDataset.Builder(dataset1).setUnknownTlvs(unknownTlvs).build(); 106 107 assertThat(dataset1.getUnknownTlvs().size()).isEqualTo(0); 108 assertThat(dataset2.getUnknownTlvs().size()).isEqualTo(2); 109 assertThat(dataset2.getUnknownTlvs().get(0x33)).isEqualTo(new byte[] {1, 2, 3}); 110 assertThat(dataset2.getUnknownTlvs().get(0x44)).isEqualTo(new byte[] {1, 2, 3, 4}); 111 } 112 113 @Test securityPolicy_fromTooShortTlvValue_throwsIllegalArgument()114 public void securityPolicy_fromTooShortTlvValue_throwsIllegalArgument() { 115 assertThrows( 116 IllegalArgumentException.class, 117 () -> SecurityPolicy.fromTlvValue(new byte[] {0x01})); 118 assertThrows( 119 IllegalArgumentException.class, 120 () -> SecurityPolicy.fromTlvValue(new byte[] {0x01, 0x02})); 121 } 122 123 @Test securityPolicy_toTlvValue_conversionIsLossLess()124 public void securityPolicy_toTlvValue_conversionIsLossLess() { 125 SecurityPolicy policy1 = new SecurityPolicy(200, new byte[] {(byte) 0xFF, (byte) 0xF8}); 126 127 SecurityPolicy policy2 = SecurityPolicy.fromTlvValue(policy1.toTlvValue()); 128 129 assertThat(policy2).isEqualTo(policy1); 130 } 131 } 132