1 /* 2 * Copyright (C) 2020 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 com.android.eventlib; 18 19 import static com.android.eventlib.truth.EventLogsSubject.assertThat; 20 21 import static java.time.temporal.ChronoUnit.SECONDS; 22 23 import android.util.Log; 24 25 import com.android.bedstead.nene.TestApis; 26 import com.android.bedstead.nene.exceptions.NeneException; 27 import com.android.bedstead.nene.exceptions.PollValueFailedException; 28 29 import com.google.errorprone.annotations.CanIgnoreReturnValue; 30 31 import java.io.Serializable; 32 import java.time.Duration; 33 import java.time.Instant; 34 35 /** Interface to interact with the results of an {@link EventLogsQuery}. */ 36 public abstract class EventLogs<E extends Event> implements Serializable { 37 38 private static final long serialVersionUID = 1; 39 40 static final Duration DEFAULT_POLL_TIMEOUT = Duration.ofMinutes(5); 41 42 // We need to set this earlier than construction otherwise we will skip all events that happen 43 // before creating the first query 44 static Instant sEarliestLogTime = Instant.now().minus(30, SECONDS); 45 46 /** 47 * Returns the {@link EventQuerier} to be used to interact with the 48 * appropriate {@link Event} store. 49 */ getQuerier()50 protected abstract EventQuerier<E> getQuerier(); 51 52 /** 53 * Ensures that future calls to {@link #get()}, {@link #next()}, and {@link #poll()} only return 54 * events which are not already logged before this call to {@link #resetLogs()}. 55 */ resetLogs()56 public static void resetLogs() { 57 // We delay 1 ms before and after to separate the cutoff from logs which are 58 // triggered immediately by the tests - this makes behaviour more predictable 59 60 try { 61 Thread.sleep(1); 62 } catch (InterruptedException e) { 63 Log.d("EventLogs", "Interrupted when sleeping during resetLogs"); 64 } 65 66 sEarliestLogTime = Instant.now(); 67 68 try { 69 Thread.sleep(1); 70 } catch (InterruptedException e) { 71 Log.d("EventLogs", "Interrupted when sleeping during resetLogs"); 72 } 73 } 74 75 /** 76 * Gets the earliest logged event matching the query which has not be returned by a previous 77 * call to {@link #poll()}, or blocks until a matching event is logged. 78 * 79 * <p>This will timeout after {@code timeout} and return null if no matching event is logged. 80 */ poll(Duration timeout)81 public E poll(Duration timeout) { 82 return getQuerier().poll(sEarliestLogTime, timeout); 83 } 84 85 /** 86 * Gets the earliest logged event matching the query which has not be returned by a previous 87 * call to {@link #poll()}, or blocks until a matching event is logged. 88 * 89 * <p>This will timeout after {@link #DEFAULT_POLL_TIMEOUT} and return null if no matching 90 * event is logged. 91 */ poll()92 public E poll() { 93 return poll(DEFAULT_POLL_TIMEOUT); 94 } 95 96 /** 97 * Returns immediately if there is an existing event matching the query which has not been 98 * returned by a previous call to {@link #poll()}, or blocks until a matching event is logged. 99 * 100 * <p>This will timeout after {@code timeout} and throw an {@link AssertionError} if no 101 * matching event is logged. 102 */ waitForEvent(Duration timeout)103 public E waitForEvent(Duration timeout) { 104 try { 105 return assertThat(this).eventOccurredWithin(timeout); 106 } catch (PollValueFailedException e) { 107 if (e.getMessage().contains("No existing activity")) { 108 String activityName = e.getMessage().split( 109 "named ", 2)[1].split(". ", 2)[0]; 110 String packageName = e.getMessage().split("package ", 2)[1] 111 .split(". ", 2)[0]; 112 113 throw new NeneException("Error finding launched activity " + activityName 114 + " in test app " + packageName 115 + " (this could mean it didn't launch or the" 116 + " package crashed). Relevant logs: " + TestApis.logcat().dump( 117 l -> l.contains(activityName) || l.contains(packageName)), e); 118 } 119 throw e; 120 } 121 } 122 123 /** 124 * Returns immediately if there is an existing event matching the query which has not be 125 * returned by a previous call to {@link #poll()}, or blocks until a matching event is logged. 126 * 127 * <p>This will timeout after {@link #DEFAULT_POLL_TIMEOUT} and throw an {@link AssertionError} 128 * if no matching event is logged. 129 */ 130 @CanIgnoreReturnValue waitForEvent()131 public E waitForEvent() { 132 return waitForEvent(DEFAULT_POLL_TIMEOUT); 133 } 134 } 135