1 /* 2 * Copyright (C) 2019 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.util; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static com.google.common.truth.Truth.assertWithMessage; 21 22 import static java.nio.charset.StandardCharsets.UTF_8; 23 24 import android.os.SystemClock; 25 26 import androidx.test.filters.SmallTest; 27 import androidx.test.runner.AndroidJUnit4; 28 29 import com.google.common.collect.Range; 30 31 import org.junit.Test; 32 import org.junit.runner.RunWith; 33 34 import java.nio.ByteBuffer; 35 import java.nio.ByteOrder; 36 import java.util.Random; 37 38 /** 39 * Internal tests for {@link StatsEvent}. 40 */ 41 @SmallTest 42 @RunWith(AndroidJUnit4.class) 43 public class StatsEventTest { 44 45 @Test testNoFields()46 public void testNoFields() { 47 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 48 final StatsEvent statsEvent = StatsEvent.newBuilder().usePooledBuffer().build(); 49 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 50 51 final int expectedAtomId = 0; 52 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 53 54 final ByteBuffer buffer = 55 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 56 57 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 58 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 59 60 assertWithMessage("Incorrect number of elements in root object") 61 .that(buffer.get()).isEqualTo(3); 62 63 assertWithMessage("First element is not timestamp") 64 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 65 66 assertWithMessage("Incorrect timestamp") 67 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 68 69 assertWithMessage("Second element is not atom id") 70 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 71 72 assertWithMessage("Incorrect atom id") 73 .that(buffer.getInt()).isEqualTo(expectedAtomId); 74 75 assertWithMessage("Third element is not errors type") 76 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS); 77 78 final int errorMask = buffer.getInt(); 79 80 assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask") 81 .that(errorMask).isEqualTo(StatsEvent.ERROR_NO_ATOM_ID); 82 83 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 84 85 statsEvent.release(); 86 } 87 88 @Test testOnlyAtomId()89 public void testOnlyAtomId() { 90 final int expectedAtomId = 109; 91 92 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 93 final StatsEvent statsEvent = StatsEvent.newBuilder() 94 .setAtomId(expectedAtomId) 95 .usePooledBuffer() 96 .build(); 97 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 98 99 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 100 101 final ByteBuffer buffer = 102 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 103 104 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 105 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 106 107 assertWithMessage("Incorrect number of elements in root object") 108 .that(buffer.get()).isEqualTo(2); 109 110 assertWithMessage("First element is not timestamp") 111 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 112 113 assertWithMessage("Incorrect timestamp") 114 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 115 116 assertWithMessage("Second element is not atom id") 117 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 118 119 assertWithMessage("Incorrect atom id") 120 .that(buffer.getInt()).isEqualTo(expectedAtomId); 121 122 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 123 124 statsEvent.release(); 125 } 126 127 @Test testIntBooleanIntInt()128 public void testIntBooleanIntInt() { 129 final int expectedAtomId = 109; 130 final int field1 = 1; 131 final boolean field2 = true; 132 final int field3 = 3; 133 final int field4 = 4; 134 135 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 136 final StatsEvent statsEvent = StatsEvent.newBuilder() 137 .setAtomId(expectedAtomId) 138 .writeInt(field1) 139 .writeBoolean(field2) 140 .writeInt(field3) 141 .writeInt(field4) 142 .usePooledBuffer() 143 .build(); 144 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 145 146 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 147 148 final ByteBuffer buffer = 149 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 150 151 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 152 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 153 154 assertWithMessage("Incorrect number of elements in root object") 155 .that(buffer.get()).isEqualTo(6); 156 157 assertWithMessage("First element is not timestamp") 158 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 159 160 assertWithMessage("Incorrect timestamp") 161 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 162 163 assertWithMessage("Second element is not atom id") 164 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 165 166 assertWithMessage("Incorrect atom id") 167 .that(buffer.getInt()).isEqualTo(expectedAtomId); 168 169 assertWithMessage("First field is not Int") 170 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 171 172 assertWithMessage("Incorrect field 1") 173 .that(buffer.getInt()).isEqualTo(field1); 174 175 assertWithMessage("Second field is not Boolean") 176 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); 177 178 assertWithMessage("Incorrect field 2") 179 .that(buffer.get()).isEqualTo(1); 180 181 assertWithMessage("Third field is not Int") 182 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 183 184 assertWithMessage("Incorrect field 3") 185 .that(buffer.getInt()).isEqualTo(field3); 186 187 assertWithMessage("Fourth field is not Int") 188 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 189 190 assertWithMessage("Incorrect field 4") 191 .that(buffer.getInt()).isEqualTo(field4); 192 193 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 194 195 statsEvent.release(); 196 } 197 198 @Test testStringFloatByteArray()199 public void testStringFloatByteArray() { 200 final int expectedAtomId = 109; 201 final String field1 = "Str 1"; 202 final float field2 = 9.334f; 203 final byte[] field3 = new byte[] { 56, 23, 89, -120 }; 204 205 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 206 final StatsEvent statsEvent = StatsEvent.newBuilder() 207 .setAtomId(expectedAtomId) 208 .writeString(field1) 209 .writeFloat(field2) 210 .writeByteArray(field3) 211 .usePooledBuffer() 212 .build(); 213 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 214 215 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 216 217 final ByteBuffer buffer = 218 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 219 220 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 221 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 222 223 assertWithMessage("Incorrect number of elements in root object") 224 .that(buffer.get()).isEqualTo(5); 225 226 assertWithMessage("First element is not timestamp") 227 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 228 229 assertWithMessage("Incorrect timestamp") 230 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 231 232 assertWithMessage("Second element is not atom id") 233 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 234 235 assertWithMessage("Incorrect atom id") 236 .that(buffer.getInt()).isEqualTo(expectedAtomId); 237 238 assertWithMessage("First field is not String") 239 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); 240 241 final String field1Actual = getStringFromByteBuffer(buffer); 242 assertWithMessage("Incorrect field 1") 243 .that(field1Actual).isEqualTo(field1); 244 245 assertWithMessage("Second field is not Float") 246 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); 247 248 assertWithMessage("Incorrect field 2") 249 .that(buffer.getFloat()).isEqualTo(field2); 250 251 assertWithMessage("Third field is not byte array") 252 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BYTE_ARRAY); 253 254 final byte[] field3Actual = getByteArrayFromByteBuffer(buffer); 255 assertWithMessage("Incorrect field 3") 256 .that(field3Actual).isEqualTo(field3); 257 258 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 259 260 statsEvent.release(); 261 } 262 263 @Test testAttributionChainLong()264 public void testAttributionChainLong() { 265 final int expectedAtomId = 109; 266 final int[] uids = new int[] { 1, 2, 3, 4, 5 }; 267 final String[] tags = new String[] { "1", "2", "3", "4", "5" }; 268 final long field2 = -230909823L; 269 270 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 271 final StatsEvent statsEvent = StatsEvent.newBuilder() 272 .setAtomId(expectedAtomId) 273 .writeAttributionChain(uids, tags) 274 .writeLong(field2) 275 .usePooledBuffer() 276 .build(); 277 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 278 279 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 280 281 final ByteBuffer buffer = 282 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 283 284 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 285 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 286 287 assertWithMessage("Incorrect number of elements in root object") 288 .that(buffer.get()).isEqualTo(4); 289 290 assertWithMessage("First element is not timestamp") 291 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 292 293 assertWithMessage("Incorrect timestamp") 294 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 295 296 assertWithMessage("Second element is not atom id") 297 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 298 299 assertWithMessage("Incorrect atom id") 300 .that(buffer.getInt()).isEqualTo(expectedAtomId); 301 302 assertWithMessage("First field is not Attribution Chain") 303 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ATTRIBUTION_CHAIN); 304 305 assertWithMessage("Incorrect number of attribution nodes") 306 .that(buffer.get()).isEqualTo((byte) uids.length); 307 308 for (int i = 0; i < tags.length; i++) { 309 assertWithMessage("Incorrect uid in Attribution Chain") 310 .that(buffer.getInt()).isEqualTo(uids[i]); 311 312 final String tag = getStringFromByteBuffer(buffer); 313 assertWithMessage("Incorrect tag in Attribution Chain") 314 .that(tag).isEqualTo(tags[i]); 315 } 316 317 assertWithMessage("Second field is not Long") 318 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 319 320 assertWithMessage("Incorrect field 2") 321 .that(buffer.getLong()).isEqualTo(field2); 322 323 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 324 325 statsEvent.release(); 326 } 327 328 @Test testKeyValuePairs()329 public void testKeyValuePairs() { 330 final int expectedAtomId = 109; 331 final SparseIntArray intMap = new SparseIntArray(); 332 final SparseLongArray longMap = new SparseLongArray(); 333 final SparseArray<String> stringMap = new SparseArray<>(); 334 final SparseArray<Float> floatMap = new SparseArray<>(); 335 intMap.put(1, -1); 336 intMap.put(2, -2); 337 stringMap.put(3, "abc"); 338 stringMap.put(4, "2h"); 339 floatMap.put(9, -234.344f); 340 341 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 342 final StatsEvent statsEvent = StatsEvent.newBuilder() 343 .setAtomId(expectedAtomId) 344 .writeKeyValuePairs(intMap, longMap, stringMap, floatMap) 345 .usePooledBuffer() 346 .build(); 347 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 348 349 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 350 351 final ByteBuffer buffer = 352 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 353 354 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 355 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 356 357 assertWithMessage("Incorrect number of elements in root object") 358 .that(buffer.get()).isEqualTo(3); 359 360 assertWithMessage("First element is not timestamp") 361 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 362 363 assertWithMessage("Incorrect timestamp") 364 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 365 366 assertWithMessage("Second element is not atom id") 367 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 368 369 assertWithMessage("Incorrect atom id") 370 .that(buffer.getInt()).isEqualTo(expectedAtomId); 371 372 assertWithMessage("First field is not KeyValuePairs") 373 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_KEY_VALUE_PAIRS); 374 375 assertWithMessage("Incorrect number of key value pairs") 376 .that(buffer.get()).isEqualTo( 377 (byte) (intMap.size() + longMap.size() + stringMap.size() 378 + floatMap.size())); 379 380 for (int i = 0; i < intMap.size(); i++) { 381 assertWithMessage("Incorrect key in intMap") 382 .that(buffer.getInt()).isEqualTo(intMap.keyAt(i)); 383 assertWithMessage("The type id of the value should be TYPE_INT in intMap") 384 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 385 assertWithMessage("Incorrect value in intMap") 386 .that(buffer.getInt()).isEqualTo(intMap.valueAt(i)); 387 } 388 389 for (int i = 0; i < longMap.size(); i++) { 390 assertWithMessage("Incorrect key in longMap") 391 .that(buffer.getInt()).isEqualTo(longMap.keyAt(i)); 392 assertWithMessage("The type id of the value should be TYPE_LONG in longMap") 393 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 394 assertWithMessage("Incorrect value in longMap") 395 .that(buffer.getLong()).isEqualTo(longMap.valueAt(i)); 396 } 397 398 for (int i = 0; i < stringMap.size(); i++) { 399 assertWithMessage("Incorrect key in stringMap") 400 .that(buffer.getInt()).isEqualTo(stringMap.keyAt(i)); 401 assertWithMessage("The type id of the value should be TYPE_STRING in stringMap") 402 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); 403 final String value = getStringFromByteBuffer(buffer); 404 assertWithMessage("Incorrect value in stringMap") 405 .that(value).isEqualTo(stringMap.valueAt(i)); 406 } 407 408 for (int i = 0; i < floatMap.size(); i++) { 409 assertWithMessage("Incorrect key in floatMap") 410 .that(buffer.getInt()).isEqualTo(floatMap.keyAt(i)); 411 assertWithMessage("The type id of the value should be TYPE_FLOAT in floatMap") 412 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); 413 assertWithMessage("Incorrect value in floatMap") 414 .that(buffer.getFloat()).isEqualTo(floatMap.valueAt(i)); 415 } 416 417 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 418 419 statsEvent.release(); 420 } 421 422 @Test testSingleAnnotations()423 public void testSingleAnnotations() { 424 final int expectedAtomId = 109; 425 final int field1 = 1; 426 final byte field1AnnotationId = 45; 427 final boolean field1AnnotationValue = false; 428 final boolean field2 = true; 429 final byte field2AnnotationId = 1; 430 final int field2AnnotationValue = 23; 431 432 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 433 final StatsEvent statsEvent = StatsEvent.newBuilder() 434 .setAtomId(expectedAtomId) 435 .writeInt(field1) 436 .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue) 437 .writeBoolean(field2) 438 .addIntAnnotation(field2AnnotationId, field2AnnotationValue) 439 .usePooledBuffer() 440 .build(); 441 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 442 443 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 444 445 final ByteBuffer buffer = 446 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 447 448 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 449 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 450 451 assertWithMessage("Incorrect number of elements in root object") 452 .that(buffer.get()).isEqualTo(4); 453 454 assertWithMessage("First element is not timestamp") 455 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 456 457 assertWithMessage("Incorrect timestamp") 458 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 459 460 assertWithMessage("Second element is not atom id") 461 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 462 463 assertWithMessage("Incorrect atom id") 464 .that(buffer.getInt()).isEqualTo(expectedAtomId); 465 466 final byte field1Header = buffer.get(); 467 final int field1AnnotationValueCount = field1Header >> 4; 468 final byte field1Type = (byte) (field1Header & 0x0F); 469 assertWithMessage("First field is not Int") 470 .that(field1Type).isEqualTo(StatsEvent.TYPE_INT); 471 assertWithMessage("First field annotation count is wrong") 472 .that(field1AnnotationValueCount).isEqualTo(1); 473 assertWithMessage("Incorrect field 1") 474 .that(buffer.getInt()).isEqualTo(field1); 475 assertWithMessage("First field's annotation id is wrong") 476 .that(buffer.get()).isEqualTo(field1AnnotationId); 477 assertWithMessage("First field's annotation type is wrong") 478 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); 479 assertWithMessage("First field's annotation value is wrong") 480 .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0); 481 482 final byte field2Header = buffer.get(); 483 final int field2AnnotationValueCount = field2Header >> 4; 484 final byte field2Type = (byte) (field2Header & 0x0F); 485 assertWithMessage("Second field is not boolean") 486 .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN); 487 assertWithMessage("Second field annotation count is wrong") 488 .that(field2AnnotationValueCount).isEqualTo(1); 489 assertWithMessage("Incorrect field 2") 490 .that(buffer.get()).isEqualTo(field2 ? 1 : 0); 491 assertWithMessage("Second field's annotation id is wrong") 492 .that(buffer.get()).isEqualTo(field2AnnotationId); 493 assertWithMessage("Second field's annotation type is wrong") 494 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 495 assertWithMessage("Second field's annotation value is wrong") 496 .that(buffer.getInt()).isEqualTo(field2AnnotationValue); 497 498 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 499 500 statsEvent.release(); 501 } 502 503 @Test testAtomIdAnnotations()504 public void testAtomIdAnnotations() { 505 final int expectedAtomId = 109; 506 final byte atomAnnotationId = 84; 507 final int atomAnnotationValue = 9; 508 final int field1 = 1; 509 final byte field1AnnotationId = 45; 510 final boolean field1AnnotationValue = false; 511 final boolean field2 = true; 512 final byte field2AnnotationId = 1; 513 final int field2AnnotationValue = 23; 514 515 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 516 final StatsEvent statsEvent = StatsEvent.newBuilder() 517 .setAtomId(expectedAtomId) 518 .addIntAnnotation(atomAnnotationId, atomAnnotationValue) 519 .writeInt(field1) 520 .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue) 521 .writeBoolean(field2) 522 .addIntAnnotation(field2AnnotationId, field2AnnotationValue) 523 .usePooledBuffer() 524 .build(); 525 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 526 527 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 528 529 final ByteBuffer buffer = 530 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 531 532 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 533 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 534 535 assertWithMessage("Incorrect number of elements in root object") 536 .that(buffer.get()).isEqualTo(4); 537 538 assertWithMessage("First element is not timestamp") 539 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 540 541 assertWithMessage("Incorrect timestamp") 542 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 543 544 final byte atomIdHeader = buffer.get(); 545 final int atomIdAnnotationValueCount = atomIdHeader >> 4; 546 final byte atomIdValueType = (byte) (atomIdHeader & 0x0F); 547 assertWithMessage("Second element is not atom id") 548 .that(atomIdValueType).isEqualTo(StatsEvent.TYPE_INT); 549 assertWithMessage("Atom id annotation count is wrong") 550 .that(atomIdAnnotationValueCount).isEqualTo(1); 551 assertWithMessage("Incorrect atom id") 552 .that(buffer.getInt()).isEqualTo(expectedAtomId); 553 assertWithMessage("Atom id's annotation id is wrong") 554 .that(buffer.get()).isEqualTo(atomAnnotationId); 555 assertWithMessage("Atom id's annotation type is wrong") 556 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 557 assertWithMessage("Atom id's annotation value is wrong") 558 .that(buffer.getInt()).isEqualTo(atomAnnotationValue); 559 560 final byte field1Header = buffer.get(); 561 final int field1AnnotationValueCount = field1Header >> 4; 562 final byte field1Type = (byte) (field1Header & 0x0F); 563 assertWithMessage("First field is not Int") 564 .that(field1Type).isEqualTo(StatsEvent.TYPE_INT); 565 assertWithMessage("First field annotation count is wrong") 566 .that(field1AnnotationValueCount).isEqualTo(1); 567 assertWithMessage("Incorrect field 1") 568 .that(buffer.getInt()).isEqualTo(field1); 569 assertWithMessage("First field's annotation id is wrong") 570 .that(buffer.get()).isEqualTo(field1AnnotationId); 571 assertWithMessage("First field's annotation type is wrong") 572 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); 573 assertWithMessage("First field's annotation value is wrong") 574 .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0); 575 576 final byte field2Header = buffer.get(); 577 final int field2AnnotationValueCount = field2Header >> 4; 578 final byte field2Type = (byte) (field2Header & 0x0F); 579 assertWithMessage("Second field is not boolean") 580 .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN); 581 assertWithMessage("Second field annotation count is wrong") 582 .that(field2AnnotationValueCount).isEqualTo(1); 583 assertWithMessage("Incorrect field 2") 584 .that(buffer.get()).isEqualTo(field2 ? 1 : 0); 585 assertWithMessage("Second field's annotation id is wrong") 586 .that(buffer.get()).isEqualTo(field2AnnotationId); 587 assertWithMessage("Second field's annotation type is wrong") 588 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 589 assertWithMessage("Second field's annotation value is wrong") 590 .that(buffer.getInt()).isEqualTo(field2AnnotationValue); 591 592 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 593 594 statsEvent.release(); 595 } 596 597 @Test testSetAtomIdNotCalledImmediately()598 public void testSetAtomIdNotCalledImmediately() { 599 final int expectedAtomId = 109; 600 final int field1 = 25; 601 final boolean field2 = true; 602 603 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 604 final StatsEvent statsEvent = StatsEvent.newBuilder() 605 .writeInt(field1) 606 .setAtomId(expectedAtomId) 607 .writeBoolean(field2) 608 .usePooledBuffer() 609 .build(); 610 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 611 612 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 613 614 final ByteBuffer buffer = 615 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 616 617 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 618 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); 619 620 assertWithMessage("Incorrect number of elements in root object") 621 .that(buffer.get()).isEqualTo(3); 622 623 assertWithMessage("First element is not timestamp") 624 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); 625 626 assertWithMessage("Incorrect timestamp") 627 .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); 628 629 assertWithMessage("Second element is not atom id") 630 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); 631 632 assertWithMessage("Incorrect atom id") 633 .that(buffer.getInt()).isEqualTo(expectedAtomId); 634 635 assertWithMessage("Third element is not errors type") 636 .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS); 637 638 final int errorMask = buffer.getInt(); 639 640 assertWithMessage("ERROR_ATOM_ID_INVALID_POSITION should be the only error in the mask") 641 .that(errorMask).isEqualTo(StatsEvent.ERROR_ATOM_ID_INVALID_POSITION); 642 643 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 644 645 statsEvent.release(); 646 } 647 648 @Test testLargePulledEvent()649 public void testLargePulledEvent() { 650 final int expectedAtomId = 10_020; 651 byte[] field1 = new byte[10 * 1024]; 652 new Random().nextBytes(field1); 653 654 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 655 final StatsEvent statsEvent = 656 StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build(); 657 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 658 659 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 660 661 final ByteBuffer buffer = 662 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 663 664 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 665 .that(buffer.get()) 666 .isEqualTo(StatsEvent.TYPE_OBJECT); 667 668 assertWithMessage("Incorrect number of elements in root object") 669 .that(buffer.get()) 670 .isEqualTo(3); 671 672 assertWithMessage("First element is not timestamp") 673 .that(buffer.get()) 674 .isEqualTo(StatsEvent.TYPE_LONG); 675 676 assertWithMessage("Incorrect timestamp") 677 .that(buffer.getLong()) 678 .isIn(Range.closed(minTimestamp, maxTimestamp)); 679 680 assertWithMessage("Second element is not atom id") 681 .that(buffer.get()) 682 .isEqualTo(StatsEvent.TYPE_INT); 683 684 assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId); 685 686 assertWithMessage("Third element is not byte array") 687 .that(buffer.get()) 688 .isEqualTo(StatsEvent.TYPE_BYTE_ARRAY); 689 690 final byte[] field1Actual = getByteArrayFromByteBuffer(buffer); 691 assertWithMessage("Incorrect field 1").that(field1Actual).isEqualTo(field1); 692 693 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 694 695 statsEvent.release(); 696 } 697 698 @Test testPulledEventOverflow()699 public void testPulledEventOverflow() { 700 final int expectedAtomId = 10_020; 701 byte[] field1 = new byte[50 * 1024]; 702 new Random().nextBytes(field1); 703 704 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 705 final StatsEvent statsEvent = 706 StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build(); 707 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 708 709 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 710 711 final ByteBuffer buffer = 712 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 713 714 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 715 .that(buffer.get()) 716 .isEqualTo(StatsEvent.TYPE_OBJECT); 717 718 assertWithMessage("Incorrect number of elements in root object") 719 .that(buffer.get()) 720 .isEqualTo(3); 721 722 assertWithMessage("First element is not timestamp") 723 .that(buffer.get()) 724 .isEqualTo(StatsEvent.TYPE_LONG); 725 726 assertWithMessage("Incorrect timestamp") 727 .that(buffer.getLong()) 728 .isIn(Range.closed(minTimestamp, maxTimestamp)); 729 730 assertWithMessage("Second element is not atom id") 731 .that(buffer.get()) 732 .isEqualTo(StatsEvent.TYPE_INT); 733 734 assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId); 735 736 assertWithMessage("Third element is not errors type") 737 .that(buffer.get()) 738 .isEqualTo(StatsEvent.TYPE_ERRORS); 739 740 final int errorMask = buffer.getInt(); 741 742 assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask") 743 .that(errorMask) 744 .isEqualTo(StatsEvent.ERROR_OVERFLOW); 745 746 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 747 748 statsEvent.release(); 749 } 750 751 @Test testPushedEventOverflow()752 public void testPushedEventOverflow() { 753 final int expectedAtomId = 10_020; 754 byte[] field1 = new byte[10 * 1024]; 755 new Random().nextBytes(field1); 756 757 final long minTimestamp = SystemClock.elapsedRealtimeNanos(); 758 final StatsEvent statsEvent = StatsEvent.newBuilder() 759 .setAtomId(expectedAtomId) 760 .writeByteArray(field1) 761 .usePooledBuffer() 762 .build(); 763 final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); 764 765 assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); 766 767 final ByteBuffer buffer = 768 ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); 769 770 assertWithMessage("Root element in buffer is not TYPE_OBJECT") 771 .that(buffer.get()) 772 .isEqualTo(StatsEvent.TYPE_OBJECT); 773 774 assertWithMessage("Incorrect number of elements in root object") 775 .that(buffer.get()) 776 .isEqualTo(3); 777 778 assertWithMessage("First element is not timestamp") 779 .that(buffer.get()) 780 .isEqualTo(StatsEvent.TYPE_LONG); 781 782 assertWithMessage("Incorrect timestamp") 783 .that(buffer.getLong()) 784 .isIn(Range.closed(minTimestamp, maxTimestamp)); 785 786 assertWithMessage("Second element is not atom id") 787 .that(buffer.get()) 788 .isEqualTo(StatsEvent.TYPE_INT); 789 790 assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId); 791 792 assertWithMessage("Third element is not errors type") 793 .that(buffer.get()) 794 .isEqualTo(StatsEvent.TYPE_ERRORS); 795 796 final int errorMask = buffer.getInt(); 797 798 assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask") 799 .that(errorMask) 800 .isEqualTo(StatsEvent.ERROR_OVERFLOW); 801 802 assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); 803 804 statsEvent.release(); 805 } 806 getByteArrayFromByteBuffer(final ByteBuffer buffer)807 private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) { 808 final int numBytes = buffer.getInt(); 809 byte[] bytes = new byte[numBytes]; 810 buffer.get(bytes); 811 return bytes; 812 } 813 getStringFromByteBuffer(final ByteBuffer buffer)814 private static String getStringFromByteBuffer(final ByteBuffer buffer) { 815 final byte[] bytes = getByteArrayFromByteBuffer(buffer); 816 return new String(bytes, UTF_8); 817 } 818 } 819