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