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