• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.cts;
18 
19 import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
20 
21 import static com.google.common.io.BaseEncoding.base16;
22 import static com.google.common.truth.Truth.assertThat;
23 
24 import static org.junit.Assert.assertThrows;
25 
26 import android.net.IpPrefix;
27 import android.net.thread.ActiveOperationalDataset;
28 import android.net.thread.ActiveOperationalDataset.SecurityPolicy;
29 import android.net.thread.OperationalDatasetTimestamp;
30 import android.net.thread.PendingOperationalDataset;
31 import android.net.thread.utils.ThreadFeatureCheckerRule;
32 import android.net.thread.utils.ThreadFeatureCheckerRule.RequiresThreadFeature;
33 import android.util.SparseArray;
34 
35 import androidx.test.ext.junit.runners.AndroidJUnit4;
36 import androidx.test.filters.SmallTest;
37 
38 import com.google.common.primitives.Bytes;
39 import com.google.common.testing.EqualsTester;
40 
41 import org.junit.Rule;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 import java.net.InetAddress;
46 import java.time.Duration;
47 
48 /** Tests for {@link PendingOperationalDataset}. */
49 @SmallTest
50 @RequiresThreadFeature
51 @RunWith(AndroidJUnit4.class)
52 public final class PendingOperationalDatasetTest {
53     @Rule public final ThreadFeatureCheckerRule mThreadRule = new ThreadFeatureCheckerRule();
54 
createActiveDataset()55     private static ActiveOperationalDataset createActiveDataset() throws Exception {
56         SparseArray<byte[]> channelMask = new SparseArray<>(1);
57         channelMask.put(0, new byte[] {0x00, 0x1f, (byte) 0xff, (byte) 0xe0});
58 
59         return new ActiveOperationalDataset.Builder()
60                 .setActiveTimestamp(new OperationalDatasetTimestamp(100, 10, false))
61                 .setExtendedPanId(new byte[] {0, 1, 2, 3, 4, 5, 6, 7})
62                 .setPanId(12345)
63                 .setNetworkName("defaultNet")
64                 .setChannel(0, 18)
65                 .setChannelMask(channelMask)
66                 .setPskc(new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15})
67                 .setNetworkKey(new byte[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1})
68                 .setMeshLocalPrefix(new IpPrefix(InetAddress.getByName("fd00::1"), 64))
69                 .setSecurityPolicy(new SecurityPolicy(672, new byte[] {(byte) 0xff, (byte) 0xf8}))
70                 .build();
71     }
72 
73     @Test
parcelable_parcelingIsLossLess()74     public void parcelable_parcelingIsLossLess() throws Exception {
75         PendingOperationalDataset dataset =
76                 new PendingOperationalDataset(
77                         createActiveDataset(),
78                         new OperationalDatasetTimestamp(31536000, 200, false),
79                         Duration.ofHours(100));
80 
81         assertParcelingIsLossless(dataset);
82     }
83 
84     @Test
equalityTests()85     public void equalityTests() throws Exception {
86         ActiveOperationalDataset activeDataset1 =
87                 new ActiveOperationalDataset.Builder(createActiveDataset())
88                         .setNetworkName("net1")
89                         .build();
90         ActiveOperationalDataset activeDataset2 =
91                 new ActiveOperationalDataset.Builder(createActiveDataset())
92                         .setNetworkName("net2")
93                         .build();
94 
95         new EqualsTester()
96                 .addEqualityGroup(
97                         new PendingOperationalDataset(
98                                 activeDataset1,
99                                 new OperationalDatasetTimestamp(31536000, 100, false),
100                                 Duration.ofMillis(0)),
101                         new PendingOperationalDataset(
102                                 activeDataset1,
103                                 new OperationalDatasetTimestamp(31536000, 100, false),
104                                 Duration.ofMillis(0)))
105                 .addEqualityGroup(
106                         new PendingOperationalDataset(
107                                 activeDataset2,
108                                 new OperationalDatasetTimestamp(31536000, 100, false),
109                                 Duration.ofMillis(0)),
110                         new PendingOperationalDataset(
111                                 activeDataset2,
112                                 new OperationalDatasetTimestamp(31536000, 100, false),
113                                 Duration.ofMillis(0)))
114                 .addEqualityGroup(
115                         new PendingOperationalDataset(
116                                 activeDataset2,
117                                 new OperationalDatasetTimestamp(15768000, 0, false),
118                                 Duration.ofMillis(0)),
119                         new PendingOperationalDataset(
120                                 activeDataset2,
121                                 new OperationalDatasetTimestamp(15768000, 0, false),
122                                 Duration.ofMillis(0)))
123                 .addEqualityGroup(
124                         new PendingOperationalDataset(
125                                 activeDataset2,
126                                 new OperationalDatasetTimestamp(15768000, 0, false),
127                                 Duration.ofMillis(100)),
128                         new PendingOperationalDataset(
129                                 activeDataset2,
130                                 new OperationalDatasetTimestamp(15768000, 0, false),
131                                 Duration.ofMillis(100)))
132                 .testEquals();
133     }
134 
135     @Test
constructor_correctValuesAreSet()136     public void constructor_correctValuesAreSet() throws Exception {
137         final ActiveOperationalDataset activeDataset = createActiveDataset();
138         PendingOperationalDataset dataset =
139                 new PendingOperationalDataset(
140                         activeDataset,
141                         new OperationalDatasetTimestamp(31536000, 200, false),
142                         Duration.ofHours(100));
143 
144         assertThat(dataset.getActiveOperationalDataset()).isEqualTo(activeDataset);
145         assertThat(dataset.getPendingTimestamp())
146                 .isEqualTo(new OperationalDatasetTimestamp(31536000, 200, false));
147         assertThat(dataset.getDelayTimer()).isEqualTo(Duration.ofHours(100));
148     }
149 
150     @Test
fromThreadTlvs_openthreadTlvs_success()151     public void fromThreadTlvs_openthreadTlvs_success() {
152         // An example Pending Operational Dataset which is generated with OpenThread CLI:
153         // Pending Timestamp: 2
154         // Active Timestamp: 1
155         // Channel: 26
156         // Channel Mask: 0x07fff800
157         // Delay: 46354
158         // Ext PAN ID: a74182f4d3f4de41
159         // Mesh Local Prefix: fd46:c1b9:e159:5574::/64
160         // Network Key: ed916e454d96fd00184f10a6f5c9e1d3
161         // Network Name: OpenThread-bff8
162         // PAN ID: 0xbff8
163         // PSKc: 264f78414adc683191863d968f72d1b7
164         // Security Policy: 672 onrc
165         final byte[] OPENTHREAD_PENDING_DATASET_TLVS =
166                 base16().lowerCase()
167                         .decode(
168                                 "0e0800000000000100003308000000000002000034040000b51200030000"
169                                         + "1a35060004001fffe00208a74182f4d3f4de410708fd46c1b9"
170                                         + "e15955740510ed916e454d96fd00184f10a6f5c9e1d3030f4f"
171                                         + "70656e5468726561642d626666380102bff80410264f78414a"
172                                         + "dc683191863d968f72d1b70c0402a0f7f8");
173 
174         PendingOperationalDataset pendingDataset =
175                 PendingOperationalDataset.fromThreadTlvs(OPENTHREAD_PENDING_DATASET_TLVS);
176 
177         ActiveOperationalDataset activeDataset = pendingDataset.getActiveOperationalDataset();
178         assertThat(pendingDataset.getPendingTimestamp().getSeconds()).isEqualTo(2L);
179         assertThat(activeDataset.getActiveTimestamp().getSeconds()).isEqualTo(1L);
180         assertThat(activeDataset.getChannel()).isEqualTo(26);
181         assertThat(activeDataset.getChannelMask().get(0))
182                 .isEqualTo(new byte[] {0x00, 0x1f, (byte) 0xff, (byte) 0xe0});
183         assertThat(pendingDataset.getDelayTimer().toMillis()).isEqualTo(46354);
184         assertThat(activeDataset.getExtendedPanId())
185                 .isEqualTo(base16().lowerCase().decode("a74182f4d3f4de41"));
186         assertThat(activeDataset.getMeshLocalPrefix())
187                 .isEqualTo(new IpPrefix("fd46:c1b9:e159:5574::/64"));
188         assertThat(activeDataset.getNetworkKey())
189                 .isEqualTo(base16().lowerCase().decode("ed916e454d96fd00184f10a6f5c9e1d3"));
190         assertThat(activeDataset.getNetworkName()).isEqualTo("OpenThread-bff8");
191         assertThat(activeDataset.getPanId()).isEqualTo(0xbff8);
192         assertThat(activeDataset.getPskc())
193                 .isEqualTo(base16().lowerCase().decode("264f78414adc683191863d968f72d1b7"));
194         assertThat(activeDataset.getSecurityPolicy().getRotationTimeHours()).isEqualTo(672);
195         assertThat(activeDataset.getSecurityPolicy().getFlags())
196                 .isEqualTo(new byte[] {(byte) 0xf7, (byte) 0xf8});
197     }
198 
199     @Test
fromThreadTlvs_completePendingDatasetTlvs_success()200     public void fromThreadTlvs_completePendingDatasetTlvs_success() throws Exception {
201         final ActiveOperationalDataset activeDataset = createActiveDataset();
202 
203         // Type Length Value
204         // 0x33 0x08 0x0000000000010000 (Pending Timestamp TLV)
205         // 0x34 0x04 0x0000012C (Delay Timer TLV)
206         final byte[] pendingTimestampAndDelayTimerTlvs =
207                 base16().decode("3308000000000001000034040000012C");
208         final byte[] pendingDatasetTlvs =
209                 Bytes.concat(pendingTimestampAndDelayTimerTlvs, activeDataset.toThreadTlvs());
210 
211         PendingOperationalDataset dataset =
212                 PendingOperationalDataset.fromThreadTlvs(pendingDatasetTlvs);
213 
214         assertThat(dataset.getActiveOperationalDataset()).isEqualTo(activeDataset);
215         assertThat(dataset.getPendingTimestamp())
216                 .isEqualTo(new OperationalDatasetTimestamp(1, 0, false));
217         assertThat(dataset.getDelayTimer()).isEqualTo(Duration.ofMillis(300));
218     }
219 
220     @Test
fromThreadTlvs_PendingTimestampTlvIsMissing_throwsIllegalArgument()221     public void fromThreadTlvs_PendingTimestampTlvIsMissing_throwsIllegalArgument()
222             throws Exception {
223         // Type Length Value
224         // 0x34 0x04 0x00000064 (Delay Timer TLV)
225         final byte[] pendingTimestampAndDelayTimerTlvs = base16().decode("34040000012C");
226         final byte[] pendingDatasetTlvs =
227                 Bytes.concat(
228                         pendingTimestampAndDelayTimerTlvs, createActiveDataset().toThreadTlvs());
229 
230         assertThrows(
231                 IllegalArgumentException.class,
232                 () -> PendingOperationalDataset.fromThreadTlvs(pendingDatasetTlvs));
233     }
234 
235     @Test
fromThreadTlvs_delayTimerTlvIsMissing_throwsIllegalArgument()236     public void fromThreadTlvs_delayTimerTlvIsMissing_throwsIllegalArgument() throws Exception {
237         // Type Length Value
238         // 0x33 0x08 0x0000000000010000 (Pending Timestamp TLV)
239         final byte[] pendingTimestampAndDelayTimerTlvs = base16().decode("33080000000000010000");
240         final byte[] pendingDatasetTlvs =
241                 Bytes.concat(
242                         pendingTimestampAndDelayTimerTlvs, createActiveDataset().toThreadTlvs());
243 
244         assertThrows(
245                 IllegalArgumentException.class,
246                 () -> PendingOperationalDataset.fromThreadTlvs(pendingDatasetTlvs));
247     }
248 
249     @Test
fromThreadTlvs_activeDatasetTlvs_throwsIllegalArgument()250     public void fromThreadTlvs_activeDatasetTlvs_throwsIllegalArgument() throws Exception {
251         final byte[] activeDatasetTlvs = createActiveDataset().toThreadTlvs();
252 
253         assertThrows(
254                 IllegalArgumentException.class,
255                 () -> PendingOperationalDataset.fromThreadTlvs(activeDatasetTlvs));
256     }
257 
258     @Test
fromThreadTlvs_malformedTlvs_throwsIllegalArgument()259     public void fromThreadTlvs_malformedTlvs_throwsIllegalArgument() {
260         final byte[] invalidTlvs = new byte[] {0x00};
261 
262         assertThrows(
263                 IllegalArgumentException.class,
264                 () -> PendingOperationalDataset.fromThreadTlvs(invalidTlvs));
265     }
266 
267     @Test
toThreadTlvs_conversionIsLossLess()268     public void toThreadTlvs_conversionIsLossLess() throws Exception {
269         PendingOperationalDataset dataset1 =
270                 new PendingOperationalDataset(
271                         createActiveDataset(),
272                         new OperationalDatasetTimestamp(31536000, 200, false),
273                         Duration.ofHours(100));
274 
275         PendingOperationalDataset dataset2 =
276                 PendingOperationalDataset.fromThreadTlvs(dataset1.toThreadTlvs());
277 
278         assertThat(dataset2).isEqualTo(dataset1);
279     }
280 }
281