1 /* 2 * Copyright (C) 2011 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; 18 19 import static android.net.NetworkStats.DEFAULT_NETWORK_NO; 20 import static android.net.NetworkStats.IFACE_ALL; 21 import static android.net.NetworkStats.METERED_NO; 22 import static android.net.NetworkStats.ROAMING_NO; 23 import static android.net.NetworkStats.SET_DEFAULT; 24 import static android.net.NetworkStats.TAG_NONE; 25 import static android.net.NetworkStats.UID_ALL; 26 import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong; 27 import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong; 28 import static android.net.NetworkStatsHistory.Entry.UNKNOWN; 29 import static android.net.NetworkStatsHistory.FIELD_ALL; 30 import static android.net.NetworkStatsHistory.FIELD_OPERATIONS; 31 import static android.net.NetworkStatsHistory.FIELD_RX_BYTES; 32 import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS; 33 import static android.net.NetworkStatsHistory.FIELD_TX_BYTES; 34 import static android.net.TrafficStats.GB_IN_BYTES; 35 import static android.net.TrafficStats.MB_IN_BYTES; 36 import static android.text.format.DateUtils.DAY_IN_MILLIS; 37 import static android.text.format.DateUtils.HOUR_IN_MILLIS; 38 import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 39 import static android.text.format.DateUtils.SECOND_IN_MILLIS; 40 import static android.text.format.DateUtils.WEEK_IN_MILLIS; 41 import static android.text.format.DateUtils.YEAR_IN_MILLIS; 42 43 import static org.junit.Assert.assertEquals; 44 import static org.junit.Assert.assertFalse; 45 import static org.junit.Assert.assertTrue; 46 47 import android.content.Context; 48 import android.os.Build; 49 import android.util.Log; 50 51 import androidx.test.InstrumentationRegistry; 52 import androidx.test.filters.SmallTest; 53 54 import com.android.frameworks.tests.net.R; 55 import com.android.testutils.DevSdkIgnoreRule; 56 import com.android.testutils.DevSdkIgnoreRunner; 57 import com.android.testutils.SkipPresubmit; 58 59 import org.junit.After; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 63 import java.io.ByteArrayInputStream; 64 import java.io.ByteArrayOutputStream; 65 import java.io.DataInputStream; 66 import java.io.DataOutputStream; 67 import java.util.Random; 68 69 @RunWith(DevSdkIgnoreRunner.class) 70 @SmallTest 71 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2) 72 public class NetworkStatsHistoryTest { 73 private static final String TAG = "NetworkStatsHistoryTest"; 74 75 private static final long TEST_START = 1194220800000L; 76 77 private NetworkStatsHistory stats; 78 79 @After tearDown()80 public void tearDown() throws Exception { 81 if (stats != null) { 82 assertConsistent(stats); 83 } 84 } 85 86 @Test testReadOriginalVersion()87 public void testReadOriginalVersion() throws Exception { 88 final Context context = InstrumentationRegistry.getContext(); 89 final DataInputStream in = 90 new DataInputStream(context.getResources().openRawResource(R.raw.history_v1)); 91 92 NetworkStatsHistory.Entry entry = null; 93 try { 94 final NetworkStatsHistory history = new NetworkStatsHistory(in); 95 assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration()); 96 97 entry = history.getValues(0, entry); 98 assertEquals(29143L, entry.rxBytes); 99 assertEquals(6223L, entry.txBytes); 100 101 entry = history.getValues(history.size() - 1, entry); 102 assertEquals(1476L, entry.rxBytes); 103 assertEquals(838L, entry.txBytes); 104 105 entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry); 106 assertEquals(332401L, entry.rxBytes); 107 assertEquals(64314L, entry.txBytes); 108 109 } finally { 110 in.close(); 111 } 112 } 113 114 @Test testRecordSingleBucket()115 public void testRecordSingleBucket() throws Exception { 116 final long BUCKET_SIZE = HOUR_IN_MILLIS; 117 stats = new NetworkStatsHistory(BUCKET_SIZE); 118 119 // record data into narrow window to get single bucket 120 stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 121 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 122 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 123 124 assertEquals(1, stats.size()); 125 assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L); 126 } 127 128 @Test testRecordEqualBuckets()129 public void testRecordEqualBuckets() throws Exception { 130 final long bucketDuration = HOUR_IN_MILLIS; 131 stats = new NetworkStatsHistory(bucketDuration); 132 133 // split equally across two buckets 134 final long recordStart = TEST_START + (bucketDuration / 2); 135 stats.recordData(recordStart, recordStart + bucketDuration, 136 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 137 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 128L, 2L, 2L)); 138 139 assertEquals(2, stats.size()); 140 assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L); 141 assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L); 142 } 143 144 @Test testRecordTouchingBuckets()145 public void testRecordTouchingBuckets() throws Exception { 146 final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS; 147 stats = new NetworkStatsHistory(BUCKET_SIZE); 148 149 // split almost completely into middle bucket, but with a few minutes 150 // overlap into neighboring buckets. total record is 20 minutes. 151 final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS; 152 final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4); 153 stats.recordData(recordStart, recordEnd, 154 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 155 ROAMING_NO, DEFAULT_NETWORK_NO, 1000L, 2000L, 5000L, 10000L, 100L)); 156 157 assertEquals(3, stats.size()); 158 // first bucket should have (1/20 of value) 159 assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L); 160 // second bucket should have (15/20 of value) 161 assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L); 162 // final bucket should have (4/20 of value) 163 assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L); 164 } 165 166 @Test testRecordGapBuckets()167 public void testRecordGapBuckets() throws Exception { 168 final long BUCKET_SIZE = HOUR_IN_MILLIS; 169 stats = new NetworkStatsHistory(BUCKET_SIZE); 170 171 // record some data today and next week with large gap 172 final long firstStart = TEST_START; 173 final long lastStart = TEST_START + WEEK_IN_MILLIS; 174 stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, 175 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 176 ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 2L, 256L, 4L, 1L)); 177 stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 178 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 179 ROAMING_NO, DEFAULT_NETWORK_NO, 64L, 1L, 512L, 8L, 2L)); 180 181 // we should have two buckets, far apart from each other 182 assertEquals(2, stats.size()); 183 assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L); 184 assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L); 185 186 // now record something in middle, spread across two buckets 187 final long middleStart = TEST_START + DAY_IN_MILLIS; 188 final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2); 189 stats.recordData(middleStart, middleEnd, 190 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 191 ROAMING_NO, DEFAULT_NETWORK_NO, 2048L, 4L, 2048L, 4L, 2L)); 192 193 // now should have four buckets, with new record in middle two buckets 194 assertEquals(4, stats.size()); 195 assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L); 196 assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L); 197 assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L); 198 assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L); 199 } 200 201 @Test testRecordOverlapBuckets()202 public void testRecordOverlapBuckets() throws Exception { 203 final long BUCKET_SIZE = HOUR_IN_MILLIS; 204 stats = new NetworkStatsHistory(BUCKET_SIZE); 205 206 // record some data in one bucket, and another overlapping buckets 207 stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 208 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 209 ROAMING_NO, DEFAULT_NETWORK_NO, 256L, 2L, 256L, 2L, 1L)); 210 final long midStart = TEST_START + (HOUR_IN_MILLIS / 2); 211 stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 212 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 213 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 1024L, 10L, 10L)); 214 215 // should have two buckets, with some data mixed together 216 assertEquals(2, stats.size()); 217 assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L); 218 assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L); 219 } 220 221 @Test testRecordEntireGapIdentical()222 public void testRecordEntireGapIdentical() throws Exception { 223 // first, create two separate histories far apart 224 final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); 225 stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L); 226 227 final long TEST_START_2 = TEST_START + DAY_IN_MILLIS; 228 final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS); 229 stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L); 230 231 // combine together with identical bucket size 232 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 233 stats.recordEntireHistory(stats1); 234 stats.recordEntireHistory(stats2); 235 236 // first verify that totals match up 237 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L); 238 239 // now inspect internal buckets 240 assertValues(stats, 0, 1000L, 500L); 241 assertValues(stats, 1, 1000L, 500L); 242 assertValues(stats, 2, 500L, 250L); 243 assertValues(stats, 3, 500L, 250L); 244 } 245 246 @Test testRecordEntireOverlapVaryingBuckets()247 public void testRecordEntireOverlapVaryingBuckets() throws Exception { 248 // create history just over hour bucket boundary 249 final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); 250 stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L); 251 252 final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS; 253 final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS); 254 stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L); 255 256 // combine together with minute bucket size 257 stats = new NetworkStatsHistory(MINUTE_IN_MILLIS); 258 stats.recordEntireHistory(stats1); 259 stats.recordEntireHistory(stats2); 260 261 // first verify that totals match up 262 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); 263 264 // now inspect internal buckets 265 assertValues(stats, 0, 10L, 10L); 266 assertValues(stats, 1, 20L, 20L); 267 assertValues(stats, 2, 20L, 20L); 268 assertValues(stats, 3, 20L, 20L); 269 assertValues(stats, 4, 20L, 20L); 270 assertValues(stats, 5, 20L, 20L); 271 assertValues(stats, 6, 10L, 10L); 272 273 // now combine using 15min buckets 274 stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4); 275 stats.recordEntireHistory(stats1); 276 stats.recordEntireHistory(stats2); 277 278 // first verify that totals match up 279 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); 280 281 // and inspect buckets 282 assertValues(stats, 0, 200L, 200L); 283 assertValues(stats, 1, 150L, 150L); 284 assertValues(stats, 2, 150L, 150L); 285 assertValues(stats, 3, 150L, 150L); 286 } 287 288 @Test testRemoveStartingBefore()289 public void testRemoveStartingBefore() throws Exception { 290 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 291 292 // record some data across 24 buckets 293 stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L); 294 assertEquals(24, stats.size()); 295 296 // try removing invalid data; should be no change 297 stats.removeBucketsStartingBefore(0 - DAY_IN_MILLIS); 298 assertEquals(24, stats.size()); 299 300 // try removing far before buckets; should be no change 301 stats.removeBucketsStartingBefore(TEST_START - YEAR_IN_MILLIS); 302 assertEquals(24, stats.size()); 303 304 // try removing just moments into first bucket; should be no change 305 // since that bucket doesn't contain data starts before the cutoff 306 stats.removeBucketsStartingBefore(TEST_START); 307 assertEquals(24, stats.size()); 308 309 // try removing single bucket 310 stats.removeBucketsStartingBefore(TEST_START + HOUR_IN_MILLIS); 311 assertEquals(23, stats.size()); 312 313 // try removing multiple buckets 314 stats.removeBucketsStartingBefore(TEST_START + (4 * HOUR_IN_MILLIS)); 315 assertEquals(20, stats.size()); 316 317 // try removing all buckets 318 stats.removeBucketsStartingBefore(TEST_START + YEAR_IN_MILLIS); 319 assertEquals(0, stats.size()); 320 } 321 322 @Test testTotalData()323 public void testTotalData() throws Exception { 324 final long BUCKET_SIZE = HOUR_IN_MILLIS; 325 stats = new NetworkStatsHistory(BUCKET_SIZE); 326 327 // record uniform data across day 328 stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L); 329 330 // verify that total outside range is 0 331 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L); 332 333 // verify total in first hour 334 assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L); 335 336 // verify total across 1.5 hours 337 assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L); 338 339 // verify total beyond end 340 assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L); 341 342 // verify everything total 343 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L); 344 345 } 346 347 @SkipPresubmit(reason = "Flaky: b/302325928; add to presubmit after fixing") 348 @Test testFuzzing()349 public void testFuzzing() throws Exception { 350 try { 351 // fuzzing with random events, looking for crashes 352 final NetworkStats.Entry entry = new NetworkStats.Entry(); 353 final Random r = new Random(); 354 for (int i = 0; i < 500; i++) { 355 stats = new NetworkStatsHistory(r.nextLong()); 356 for (int j = 0; j < 10000; j++) { 357 if (r.nextBoolean()) { 358 // add range 359 final long start = r.nextLong(); 360 final long end = start + r.nextInt(); 361 entry.rxBytes = nextPositiveLong(r); 362 entry.rxPackets = nextPositiveLong(r); 363 entry.txBytes = nextPositiveLong(r); 364 entry.txPackets = nextPositiveLong(r); 365 entry.operations = nextPositiveLong(r); 366 stats.recordData(start, end, entry); 367 } else { 368 // trim something 369 stats.removeBucketsStartingBefore(r.nextLong()); 370 } 371 } 372 assertConsistent(stats); 373 } 374 } catch (Throwable e) { 375 Log.e(TAG, String.valueOf(stats)); 376 throw new RuntimeException(e); 377 } 378 } 379 nextPositiveLong(Random r)380 private static long nextPositiveLong(Random r) { 381 final long value = r.nextLong(); 382 return value < 0 ? -value : value; 383 } 384 385 @Test testIgnoreFields()386 public void testIgnoreFields() throws Exception { 387 final NetworkStatsHistory history = new NetworkStatsHistory( 388 MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES); 389 390 history.recordData(0, MINUTE_IN_MILLIS, 391 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 392 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L)); 393 history.recordData(0, 2 * MINUTE_IN_MILLIS, 394 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 395 ROAMING_NO, DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 2L)); 396 397 assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN); 398 } 399 400 @Test testIgnoreFieldsRecordIn()401 public void testIgnoreFieldsRecordIn() throws Exception { 402 final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL); 403 final NetworkStatsHistory partial = new NetworkStatsHistory( 404 MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS); 405 406 full.recordData(0, MINUTE_IN_MILLIS, 407 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 408 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L)); 409 partial.recordEntireHistory(full); 410 411 assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L); 412 } 413 414 @Test testIgnoreFieldsRecordOut()415 public void testIgnoreFieldsRecordOut() throws Exception { 416 final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL); 417 final NetworkStatsHistory partial = new NetworkStatsHistory( 418 MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS); 419 420 partial.recordData(0, MINUTE_IN_MILLIS, 421 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 422 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L)); 423 full.recordEntireHistory(partial); 424 425 assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L); 426 } 427 428 @Test testSerialize()429 public void testSerialize() throws Exception { 430 final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL); 431 before.recordData(0, 4 * MINUTE_IN_MILLIS, 432 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 433 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 4L)); 434 before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS, 435 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 436 ROAMING_NO, DEFAULT_NETWORK_NO, 10L, 20L, 30L, 40L, 50L)); 437 438 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 439 before.writeToStream(new DataOutputStream(out)); 440 out.close(); 441 442 final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); 443 final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in)); 444 445 // must have identical totals before and after 446 assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L); 447 assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L); 448 } 449 450 @Test testVarLong()451 public void testVarLong() throws Exception { 452 assertEquals(0L, performVarLong(0L)); 453 assertEquals(-1L, performVarLong(-1L)); 454 assertEquals(1024L, performVarLong(1024L)); 455 assertEquals(-1024L, performVarLong(-1024L)); 456 assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES)); 457 assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES)); 458 assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE)); 459 assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE)); 460 assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40)); 461 assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40)); 462 } 463 464 @Test testIndexBeforeAfter()465 public void testIndexBeforeAfter() throws Exception { 466 final long BUCKET_SIZE = HOUR_IN_MILLIS; 467 stats = new NetworkStatsHistory(BUCKET_SIZE); 468 469 final long FIRST_START = TEST_START; 470 final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS); 471 final long SECOND_START = TEST_START + WEEK_IN_MILLIS; 472 final long SECOND_END = SECOND_START + HOUR_IN_MILLIS; 473 final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS); 474 final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS); 475 476 stats.recordData(FIRST_START, FIRST_END, 477 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 478 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 479 stats.recordData(SECOND_START, SECOND_END, 480 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 481 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 482 stats.recordData(THIRD_START, THIRD_END, 483 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 484 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 485 486 // should have buckets: 2+1+2 487 assertEquals(5, stats.size()); 488 489 assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE); 490 assertIndexBeforeAfter(stats, 0, 1, FIRST_START); 491 assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS); 492 assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS); 493 assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS); 494 assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS); 495 assertIndexBeforeAfter(stats, 1, 2, FIRST_END); 496 assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS); 497 assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS); 498 assertIndexBeforeAfter(stats, 1, 3, SECOND_START); 499 assertIndexBeforeAfter(stats, 2, 3, SECOND_END); 500 assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS); 501 assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS); 502 assertIndexBeforeAfter(stats, 2, 4, THIRD_START); 503 assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS); 504 assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS); 505 assertIndexBeforeAfter(stats, 4, 4, THIRD_END); 506 assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS); 507 assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE); 508 } 509 510 @Test testIntersects()511 public void testIntersects() throws Exception { 512 final long BUCKET_SIZE = HOUR_IN_MILLIS; 513 stats = new NetworkStatsHistory(BUCKET_SIZE); 514 515 final long FIRST_START = TEST_START; 516 final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS); 517 final long SECOND_START = TEST_START + WEEK_IN_MILLIS; 518 final long SECOND_END = SECOND_START + HOUR_IN_MILLIS; 519 final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS); 520 final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS); 521 522 stats.recordData(FIRST_START, FIRST_END, 523 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 524 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 525 stats.recordData(SECOND_START, SECOND_END, 526 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 527 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 528 stats.recordData(THIRD_START, THIRD_END, 529 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 530 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 531 532 assertFalse(stats.intersects(10, 20)); 533 assertFalse(stats.intersects(TEST_START + YEAR_IN_MILLIS, TEST_START + YEAR_IN_MILLIS + 1)); 534 assertFalse(stats.intersects(Long.MAX_VALUE, Long.MIN_VALUE)); 535 536 assertTrue(stats.intersects(Long.MIN_VALUE, Long.MAX_VALUE)); 537 assertTrue(stats.intersects(10, TEST_START + YEAR_IN_MILLIS)); 538 assertTrue(stats.intersects(TEST_START, TEST_START)); 539 assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, TEST_START + DAY_IN_MILLIS + 1)); 540 assertTrue(stats.intersects(TEST_START + DAY_IN_MILLIS, Long.MAX_VALUE)); 541 assertTrue(stats.intersects(TEST_START + 1, Long.MAX_VALUE)); 542 543 assertFalse(stats.intersects(Long.MIN_VALUE, TEST_START - 1)); 544 assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START)); 545 assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1)); 546 } 547 548 @Test testSetValues()549 public void testSetValues() throws Exception { 550 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 551 stats.recordData(TEST_START, TEST_START + 1, 552 new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, 553 ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 10L, 2048L, 20L, 2L)); 554 555 assertEquals(1024L + 2048L, stats.getTotalBytes()); 556 557 final NetworkStatsHistory.Entry entry = stats.getValues(0, null); 558 entry.rxBytes /= 2; 559 entry.txBytes *= 2; 560 stats.setValues(0, entry); 561 562 assertEquals(512L + 4096L, stats.getTotalBytes()); 563 } 564 assertIndexBeforeAfter( NetworkStatsHistory stats, int before, int after, long time)565 private static void assertIndexBeforeAfter( 566 NetworkStatsHistory stats, int before, int after, long time) { 567 assertEquals("unexpected before", before, stats.getIndexBefore(time)); 568 assertEquals("unexpected after", after, stats.getIndexAfter(time)); 569 } 570 performVarLong(long before)571 private static long performVarLong(long before) throws Exception { 572 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 573 writeVarLong(new DataOutputStream(out), before); 574 575 final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); 576 return readVarLong(new DataInputStream(in)); 577 } 578 assertConsistent(NetworkStatsHistory stats)579 private static void assertConsistent(NetworkStatsHistory stats) { 580 // verify timestamps are monotonic 581 long lastStart = Long.MIN_VALUE; 582 NetworkStatsHistory.Entry entry = null; 583 for (int i = 0; i < stats.size(); i++) { 584 entry = stats.getValues(i, entry); 585 assertTrue(lastStart < entry.bucketStart); 586 lastStart = entry.bucketStart; 587 } 588 } 589 590 private static void assertValues( 591 NetworkStatsHistory stats, int index, long rxBytes, long txBytes) { 592 final NetworkStatsHistory.Entry entry = stats.getValues(index, null); 593 assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); 594 assertEquals("unexpected txBytes", txBytes, entry.txBytes); 595 } 596 597 private static void assertValues( 598 NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { 599 final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); 600 assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); 601 assertEquals("unexpected txBytes", txBytes, entry.txBytes); 602 } 603 604 private static void assertValues(NetworkStatsHistory stats, int index, long activeTime, 605 long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { 606 final NetworkStatsHistory.Entry entry = stats.getValues(index, null); 607 assertEquals("unexpected activeTime", activeTime, entry.activeTime); 608 assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); 609 assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); 610 assertEquals("unexpected txBytes", txBytes, entry.txBytes); 611 assertEquals("unexpected txPackets", txPackets, entry.txPackets); 612 assertEquals("unexpected operations", operations, entry.operations); 613 } 614 615 private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes, 616 long rxPackets, long txBytes, long txPackets, long operations) { 617 assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes, 618 txPackets, operations); 619 } 620 621 private static void assertValues(NetworkStatsHistory stats, long start, long end, 622 long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets, 623 long operations) { 624 final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); 625 assertEquals("unexpected activeTime", activeTime, entry.activeTime); 626 assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); 627 assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); 628 assertEquals("unexpected txBytes", txBytes, entry.txBytes); 629 assertEquals("unexpected txPackets", txPackets, entry.txPackets); 630 assertEquals("unexpected operations", operations, entry.operations); 631 } 632 } 633