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