NetworkStatsHistoryTest.java revision 434962e44ea93b1c4d216c55f636a435bf54aa54
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.size()); 58 assertValues(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.size()); 70 assertValues(stats, 0, 512L, 64L); 71 assertValues(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.size()); 85 // first bucket should have (1/20 of value) 86 assertValues(stats, 0, 50L, 250L); 87 // second bucket should have (15/20 of value) 88 assertValues(stats, 1, 750L, 3750L); 89 // final bucket should have (4/20 of value) 90 assertValues(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.size()); 105 assertValues(stats, 0, 128L, 256L); 106 assertValues(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.size()); 115 assertValues(stats, 0, 128L, 256L); 116 assertValues(stats, 1, 1024L, 1024L); 117 assertValues(stats, 2, 1024L, 1024L); 118 assertValues(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.size()); 132 assertValues(stats, 0, 768L, 768L); 133 assertValues(stats, 1, 512L, 512L); 134 } 135 136 public void testRecordEntireGapIdentical() throws Exception { 137 // first, create two separate histories far apart 138 final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); 139 stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L); 140 141 final long TEST_START_2 = TEST_START + DAY_IN_MILLIS; 142 final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS); 143 stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L); 144 145 // combine together with identical bucket size 146 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 147 stats.recordEntireHistory(stats1); 148 stats.recordEntireHistory(stats2); 149 150 // first verify that totals match up 151 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L); 152 153 // now inspect internal buckets 154 assertValues(stats, 0, 1000L, 500L); 155 assertValues(stats, 1, 1000L, 500L); 156 assertValues(stats, 2, 500L, 250L); 157 assertValues(stats, 3, 500L, 250L); 158 } 159 160 public void testRecordEntireOverlapVaryingBuckets() throws Exception { 161 // create history just over hour bucket boundary 162 final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); 163 stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L); 164 165 final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS; 166 final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS); 167 stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L); 168 169 // combine together with minute bucket size 170 stats = new NetworkStatsHistory(MINUTE_IN_MILLIS); 171 stats.recordEntireHistory(stats1); 172 stats.recordEntireHistory(stats2); 173 174 // first verify that totals match up 175 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); 176 177 // now inspect internal buckets 178 assertValues(stats, 0, 10L, 10L); 179 assertValues(stats, 1, 20L, 20L); 180 assertValues(stats, 2, 20L, 20L); 181 assertValues(stats, 3, 20L, 20L); 182 assertValues(stats, 4, 20L, 20L); 183 assertValues(stats, 5, 20L, 20L); 184 assertValues(stats, 6, 10L, 10L); 185 186 // now combine using 15min buckets 187 stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4); 188 stats.recordEntireHistory(stats1); 189 stats.recordEntireHistory(stats2); 190 191 // first verify that totals match up 192 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); 193 194 // and inspect buckets 195 assertValues(stats, 0, 200L, 200L); 196 assertValues(stats, 1, 150L, 150L); 197 assertValues(stats, 2, 150L, 150L); 198 assertValues(stats, 3, 150L, 150L); 199 } 200 201 public void testRemove() throws Exception { 202 stats = new NetworkStatsHistory(HOUR_IN_MILLIS); 203 204 // record some data across 24 buckets 205 stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L); 206 assertEquals(24, stats.size()); 207 208 // try removing far before buckets; should be no change 209 stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS); 210 assertEquals(24, stats.size()); 211 212 // try removing just moments into first bucket; should be no change 213 // since that bucket contains data beyond the cutoff 214 stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS); 215 assertEquals(24, stats.size()); 216 217 // try removing single bucket 218 stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS); 219 assertEquals(23, stats.size()); 220 221 // try removing multiple buckets 222 stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS)); 223 assertEquals(20, stats.size()); 224 225 // try removing all buckets 226 stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS); 227 assertEquals(0, stats.size()); 228 } 229 230 public void testTotalData() throws Exception { 231 final long BUCKET_SIZE = HOUR_IN_MILLIS; 232 stats = new NetworkStatsHistory(BUCKET_SIZE); 233 234 // record uniform data across day 235 stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L); 236 237 // verify that total outside range is 0 238 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L); 239 240 // verify total in first hour 241 assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L); 242 243 // verify total across 1.5 hours 244 assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L); 245 246 // verify total beyond end 247 assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L); 248 249 // verify everything total 250 assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L); 251 252 } 253 254 @Suppress 255 public void testFuzzing() throws Exception { 256 try { 257 // fuzzing with random events, looking for crashes 258 final Random r = new Random(); 259 for (int i = 0; i < 500; i++) { 260 stats = new NetworkStatsHistory(r.nextLong()); 261 for (int j = 0; j < 10000; j++) { 262 if (r.nextBoolean()) { 263 // add range 264 final long start = r.nextLong(); 265 final long end = start + r.nextInt(); 266 stats.recordData(start, end, r.nextLong(), r.nextLong()); 267 } else { 268 // trim something 269 stats.removeBucketsBefore(r.nextLong()); 270 } 271 } 272 assertConsistent(stats); 273 } 274 } catch (Throwable e) { 275 Log.e(TAG, String.valueOf(stats)); 276 throw new RuntimeException(e); 277 } 278 } 279 280 private static void assertConsistent(NetworkStatsHistory stats) { 281 // verify timestamps are monotonic 282 long lastStart = Long.MIN_VALUE; 283 NetworkStatsHistory.Entry entry = null; 284 for (int i = 0; i < stats.size(); i++) { 285 entry = stats.getValues(i, entry); 286 assertTrue(lastStart < entry.bucketStart); 287 lastStart = entry.bucketStart; 288 } 289 } 290 291 private static void assertValues( 292 NetworkStatsHistory stats, int index, long rxBytes, long txBytes) { 293 final NetworkStatsHistory.Entry entry = stats.getValues(index, null); 294 assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); 295 assertEquals("unexpected txBytes", txBytes, entry.txBytes); 296 } 297 298 private static void assertValues( 299 NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { 300 final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); 301 assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); 302 assertEquals("unexpected txBytes", txBytes, entry.txBytes); 303 } 304 305} 306