NetworkStatsHistoryTest.java revision 19862bf5d058b6ab0c2979e7a5e0297dae6b170b
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 17package android.net; 18 19import static android.text.format.DateUtils.DAY_IN_MILLIS; 20import static android.text.format.DateUtils.HOUR_IN_MILLIS; 21import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 22import static android.text.format.DateUtils.SECOND_IN_MILLIS; 23import static android.text.format.DateUtils.WEEK_IN_MILLIS; 24import static android.text.format.DateUtils.YEAR_IN_MILLIS; 25 26import android.test.suitebuilder.annotation.SmallTest; 27import android.test.suitebuilder.annotation.Suppress; 28import android.util.Log; 29 30import junit.framework.TestCase; 31 32import java.util.Random; 33 34@SmallTest 35public class NetworkStatsHistoryTest extends TestCase { 36 private static final String TAG = "NetworkStatsHistoryTest"; 37 38 private static final long TEST_START = 1194220800000L; 39 40 private NetworkStatsHistory stats; 41 42 @Override 43 protected void tearDown() throws Exception { 44 super.tearDown(); 45 if (stats != null) { 46 assertConsistent(stats); 47 } 48 } 49 50 public void testRecordSingleBucket() throws Exception { 51 final long BUCKET_SIZE = HOUR_IN_MILLIS; 52 stats = new NetworkStatsHistory(BUCKET_SIZE); 53 54 // record data into narrow window to get single bucket 55 stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 1024L, 2048L); 56 57 assertEquals(1, stats.bucketCount); 58 assertBucket(stats, 0, 1024L, 2048L); 59 } 60 61 public void testRecordEqualBuckets() throws Exception { 62 final long bucketDuration = HOUR_IN_MILLIS; 63 stats = new NetworkStatsHistory(bucketDuration); 64 65 // split equally across two buckets 66 final long recordStart = TEST_START + (bucketDuration / 2); 67 stats.recordData(recordStart, recordStart + bucketDuration, 1024L, 128L); 68 69 assertEquals(2, stats.bucketCount); 70 assertBucket(stats, 0, 512L, 64L); 71 assertBucket(stats, 1, 512L, 64L); 72 } 73 74 public void testRecordTouchingBuckets() throws Exception { 75 final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS; 76 stats = new NetworkStatsHistory(BUCKET_SIZE); 77 78 // split almost completely into middle bucket, but with a few minutes 79 // overlap into neighboring buckets. total record is 20 minutes. 80 final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS; 81 final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4); 82 stats.recordData(recordStart, recordEnd, 1000L, 5000L); 83 84 assertEquals(3, stats.bucketCount); 85 // first bucket should have (1/20 of value) 86 assertBucket(stats, 0, 50L, 250L); 87 // second bucket should have (15/20 of value) 88 assertBucket(stats, 1, 750L, 3750L); 89 // final bucket should have (4/20 of value) 90 assertBucket(stats, 2, 200L, 1000L); 91 } 92 93 public void testRecordGapBuckets() throws Exception { 94 final long BUCKET_SIZE = HOUR_IN_MILLIS; 95 stats = new NetworkStatsHistory(BUCKET_SIZE); 96 97 // record some data today and next week with large gap 98 final long firstStart = TEST_START; 99 final long lastStart = TEST_START + WEEK_IN_MILLIS; 100 stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, 128L, 256L); 101 stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, 64L, 512L); 102 103 // we should have two buckets, far apart from each other 104 assertEquals(2, stats.bucketCount); 105 assertBucket(stats, 0, 128L, 256L); 106 assertBucket(stats, 1, 64L, 512L); 107 108 // now record something in middle, spread across two buckets 109 final long middleStart = TEST_START + DAY_IN_MILLIS; 110 final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2); 111 stats.recordData(middleStart, middleEnd, 2048L, 2048L); 112 113 // now should have four buckets, with new record in middle two buckets 114 assertEquals(4, stats.bucketCount); 115 assertBucket(stats, 0, 128L, 256L); 116 assertBucket(stats, 1, 1024L, 1024L); 117 assertBucket(stats, 2, 1024L, 1024L); 118 assertBucket(stats, 3, 64L, 512L); 119 } 120 121 public void testRecordOverlapBuckets() throws Exception { 122 final long BUCKET_SIZE = HOUR_IN_MILLIS; 123 stats = new NetworkStatsHistory(BUCKET_SIZE); 124 125 // record some data in one bucket, and another overlapping buckets 126 stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, 256L, 256L); 127 final long midStart = TEST_START + (HOUR_IN_MILLIS / 2); 128 stats.recordData(midStart, midStart + HOUR_IN_MILLIS, 1024L, 1024L); 129 130 // should have two buckets, with some data mixed together 131 assertEquals(2, stats.bucketCount); 132 assertBucket(stats, 0, 768L, 768L); 133 assertBucket(stats, 1, 512L, 512L); 134 } 135 136 public void testRecordEntireGapIdentical() throws Exception { 137 final long[] total = new long[2]; 138 139 // first, create two separate histories far apart 140 final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); 141 stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L); 142 143 final long TEST_START_2 = TEST_START + DAY_IN_MILLIS; 144 final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS); 145 stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L); 146 147 // combine together with identical bucket size 148 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 149 stats.recordEntireHistory(stats1); 150 stats.recordEntireHistory(stats2); 151 152 // first verify that totals match up 153 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); 154 assertTotalEquals(total, 3000L, 1500L); 155 156 // now inspect internal buckets 157 assertBucket(stats, 0, 1000L, 500L); 158 assertBucket(stats, 1, 1000L, 500L); 159 assertBucket(stats, 2, 500L, 250L); 160 assertBucket(stats, 3, 500L, 250L); 161 } 162 163 public void testRecordEntireOverlapVaryingBuckets() throws Exception { 164 final long[] total = new long[2]; 165 166 // create history just over hour bucket boundary 167 final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); 168 stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L); 169 170 final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS; 171 final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS); 172 stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L); 173 174 // combine together with minute bucket size 175 stats = new NetworkStatsHistory(MINUTE_IN_MILLIS); 176 stats.recordEntireHistory(stats1); 177 stats.recordEntireHistory(stats2); 178 179 // first verify that totals match up 180 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); 181 assertTotalEquals(total, 650L, 650L); 182 183 // now inspect internal buckets 184 assertBucket(stats, 0, 10L, 10L); 185 assertBucket(stats, 1, 20L, 20L); 186 assertBucket(stats, 2, 20L, 20L); 187 assertBucket(stats, 3, 20L, 20L); 188 assertBucket(stats, 4, 20L, 20L); 189 assertBucket(stats, 5, 20L, 20L); 190 assertBucket(stats, 6, 10L, 10L); 191 192 // now combine using 15min buckets 193 stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4); 194 stats.recordEntireHistory(stats1); 195 stats.recordEntireHistory(stats2); 196 197 // first verify that totals match up 198 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); 199 assertTotalEquals(total, 650L, 650L); 200 201 // and inspect buckets 202 assertBucket(stats, 0, 200L, 200L); 203 assertBucket(stats, 1, 150L, 150L); 204 assertBucket(stats, 2, 150L, 150L); 205 assertBucket(stats, 3, 150L, 150L); 206 } 207 208 public void testRemove() throws Exception { 209 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 210 211 // record some data across 24 buckets 212 stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L); 213 assertEquals(24, stats.bucketCount); 214 215 // try removing far before buckets; should be no change 216 stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS); 217 assertEquals(24, stats.bucketCount); 218 219 // try removing just moments into first bucket; should be no change 220 // since that bucket contains data beyond the cutoff 221 stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS); 222 assertEquals(24, stats.bucketCount); 223 224 // try removing single bucket 225 stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS); 226 assertEquals(23, stats.bucketCount); 227 228 // try removing multiple buckets 229 stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS)); 230 assertEquals(20, stats.bucketCount); 231 232 // try removing all buckets 233 stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS); 234 assertEquals(0, stats.bucketCount); 235 } 236 237 public void testTotalData() throws Exception { 238 final long BUCKET_SIZE = HOUR_IN_MILLIS; 239 stats = new NetworkStatsHistory(BUCKET_SIZE); 240 241 // record uniform data across day 242 stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L); 243 244 final long[] total = new long[2]; 245 246 // verify that total outside range is 0 247 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, total); 248 assertTotalEquals(total, 0, 0); 249 250 // verify total in first hour 251 stats.getTotalData(TEST_START, TEST_START + HOUR_IN_MILLIS, total); 252 assertTotalEquals(total, 100, 200); 253 254 // verify total across 1.5 hours 255 stats.getTotalData(TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), total); 256 assertTotalEquals(total, 150, 300); 257 258 // verify total beyond end 259 stats.getTotalData(TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, total); 260 assertTotalEquals(total, 100, 200); 261 262 // verify everything total 263 stats.getTotalData(TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, total); 264 assertTotalEquals(total, 2400, 4800); 265 266 } 267 268 @Suppress 269 public void testFuzzing() throws Exception { 270 try { 271 // fuzzing with random events, looking for crashes 272 final Random r = new Random(); 273 for (int i = 0; i < 500; i++) { 274 stats = new NetworkStatsHistory(r.nextLong()); 275 for (int j = 0; j < 10000; j++) { 276 if (r.nextBoolean()) { 277 // add range 278 final long start = r.nextLong(); 279 final long end = start + r.nextInt(); 280 stats.recordData(start, end, r.nextLong(), r.nextLong()); 281 } else { 282 // trim something 283 stats.removeBucketsBefore(r.nextLong()); 284 } 285 } 286 assertConsistent(stats); 287 } 288 } catch (Throwable e) { 289 Log.e(TAG, String.valueOf(stats)); 290 throw new RuntimeException(e); 291 } 292 } 293 294 private static void assertConsistent(NetworkStatsHistory stats) { 295 // verify timestamps are monotonic 296 for (int i = 1; i < stats.bucketCount; i++) { 297 assertTrue(stats.bucketStart[i - 1] < stats.bucketStart[i]); 298 } 299 } 300 301 private static void assertTotalEquals(long[] total, long rx, long tx) { 302 assertEquals("unexpected rx", rx, total[0]); 303 assertEquals("unexpected tx", tx, total[1]); 304 } 305 306 private static void assertBucket(NetworkStatsHistory stats, int index, long rx, long tx) { 307 assertEquals("unexpected rx", rx, stats.rx[index]); 308 assertEquals("unexpected tx", tx, stats.tx[index]); 309 } 310 311} 312