1 /* 2 * Copyright (C) 2024 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 package com.android.adservices.shared.testing.concurrency; 17 18 import static com.android.adservices.shared.testing.concurrency.FailableResultSyncCallback.MSG_WRONG_ERROR_RECEIVED; 19 20 import static org.junit.Assert.assertThrows; 21 22 import com.android.adservices.shared.testing.Nullable; 23 24 import org.junit.Test; 25 26 import java.util.List; 27 28 // TODO(b/342448771): make it package protected (must move some subclass to this package first) 29 /** Base test for classes that extend FailableResultSyncCallback. */ 30 public abstract class FailableResultSyncCallbackTestCase< 31 R, F, CB extends FailableResultSyncCallback<R, F>> 32 extends IResultSyncCallbackTestCase<R, CB> { 33 34 /** Returns a new failure. */ newFailure()35 protected abstract F newFailure(); 36 37 /** 38 * Returns a class that is not the same as the class of objects returned by {@link 39 * #newFailure()} . 40 */ getClassOfDifferentFailure()41 protected abstract Class<?> getClassOfDifferentFailure(); 42 43 @Test testNewFailureAndGetClassOfDifferentFailure()44 public final void testNewFailureAndGetClassOfDifferentFailure() { 45 Class<?> clazz1 = getClassOfDifferentFailure(); 46 expect.withMessage("1st call to getClassOfdifferentFailure()").that(clazz1).isNotNull(); 47 48 Class<?> clazz2 = getClassOfDifferentFailure(); 49 expect.withMessage("2nd call to getClassOfdifferentFailure()").that(clazz2).isNotNull(); 50 expect.withMessage("2nd call to getClassOfdifferentFailure()") 51 .that(clazz2) 52 .isSameInstanceAs(clazz1); 53 54 F failure1 = newFailure(); 55 expect.withMessage("1st failure").that(failure1).isNotNull(); 56 expect.withMessage("1st failure").that(failure1).isNotInstanceOf(clazz1); 57 58 F failure2 = newFailure(); 59 expect.withMessage("2nd failure").that(failure2).isNotNull(); 60 expect.withMessage("2nd failure").that(failure2).isNotSameInstanceAs(failure1); 61 expect.withMessage("2nd failure").that(failure2).isNotInstanceOf(clazz1); 62 } 63 64 @Test testInjectResult_checkFailure()65 public final void testInjectResult_checkFailure() throws Exception { 66 assertInitialState(mCallback); 67 R injectedResult = null; 68 69 runAsync(INJECTION_TIMEOUT_MS, () -> mCallback.injectResult(injectedResult)); 70 mCallback.assertCalled(); 71 72 String when = "after injectFailure()"; 73 assertGetResultMethods(mCallback, when, injectedResult); 74 assertGetFailureMethodsWhenNoFailure(mCallback, when); 75 } 76 77 @Test testInjectFailure_null()78 public final void testInjectFailure_null() { 79 assertThrows(NullPointerException.class, () -> mCallback.injectFailure(null)); 80 } 81 82 @Test testInjectFailure()83 public final void testInjectFailure() throws Exception { 84 F failure = newFailure(); 85 assertInitialState(mCallback); 86 87 runAsync(INJECTION_TIMEOUT_MS, () -> mCallback.injectFailure(failure)); 88 89 F receivedFailure = mCallback.assertFailureReceived(); 90 91 expect.withMessage("%s.assertFailureReceived()", mCallback) 92 .that(receivedFailure) 93 .isSameInstanceAs(failure); 94 expect.withMessage("%s.isCalled() after assertFailureReceived()", mCallback) 95 .that(mCallback.isCalled()) 96 .isTrue(); 97 98 String when = "after assertFailureReceived()"; 99 assertGetFailureMethods(mCallback, when, failure); 100 assertGetResultMethodsWhenNoResult(mCallback, when); 101 } 102 103 @Test testInjectFailure_calledTwice()104 public final void testInjectFailure_calledTwice() throws Exception { 105 F failure = newFailure(); 106 F anotherFailure = newFailure(); 107 mCallback.injectFailure(failure); 108 mCallback.injectFailure(anotherFailure); 109 110 mCallback.assertFailureReceived(); 111 112 String when = "after 2 injectFailure() calls"; 113 assertGetResultMethodsWhenNoResult(mCallback, when); 114 assertGetFailureMethods(mCallback, when, failure, anotherFailure); 115 } 116 117 @Test testInjectFailure_calledAfterInjectResult()118 public final void testInjectFailure_calledAfterInjectResult() throws Exception { 119 String when = "after injectResult() and injectFailure()"; 120 R result = null; 121 F failure = newFailure(); 122 mCallback.injectResult(result); 123 mCallback.injectFailure(failure); 124 125 mCallback.assertFailureReceived(); 126 127 assertGetResultMethods(mCallback, when, result); 128 assertGetFailureMethodsWhenInjectedResultWasCalledFirst(mCallback, when, failure); 129 } 130 131 @Test testInjectResult_calledAfterInjectFailure()132 public final void testInjectResult_calledAfterInjectFailure() throws Exception { 133 R result = null; 134 F failure = newFailure(); 135 mCallback.injectFailure(failure); 136 mCallback.injectResult(result); 137 138 F failureReceived = mCallback.assertFailureReceived(); 139 expect.withMessage("%s.assertFailureReceived()", mCallback) 140 .that(failureReceived) 141 .isSameInstanceAs(failure); 142 143 String when = "after injectFailure() and injectResult()"; 144 assertGetFailureMethods(mCallback, when, failure); 145 assertGetResultMethods(mCallback, when, result); 146 } 147 148 @Test testAssertFailureReceived_null()149 public final void testAssertFailureReceived_null() throws Exception { 150 assertThrows(NullPointerException.class, () -> mCallback.assertFailureReceived(null)); 151 } 152 153 @Test testAssertFailureReceived_rightClass()154 public final void testAssertFailureReceived_rightClass() throws Exception { 155 F failure = newFailure(); 156 mCallback.injectFailure(failure); 157 @SuppressWarnings("unchecked") 158 Class<F> subFailureClass = (Class<F>) failure.getClass(); 159 160 F failureReceived = mCallback.assertFailureReceived(subFailureClass); 161 162 expect.withMessage("%s.assertFailureReceived(...)", mCallback) 163 .that(failureReceived) 164 .isSameInstanceAs(failure); 165 } 166 167 @Test testAssertFailureReceived_wrongClass()168 public final void testAssertFailureReceived_wrongClass() throws Exception { 169 @SuppressWarnings("unchecked") 170 Class<F> subFailureClass = (Class<F>) getClassOfDifferentFailure(); 171 F failure = newFailure(); 172 mCallback.injectFailure(failure); 173 174 IllegalStateException thrown = 175 assertThrows( 176 IllegalStateException.class, 177 () -> mCallback.assertFailureReceived(subFailureClass)); 178 179 expect.withMessage("thrown") 180 .that(thrown) 181 .hasMessageThat() 182 .isEqualTo(String.format(MSG_WRONG_ERROR_RECEIVED, subFailureClass, failure)); 183 } 184 185 @Test testGetFailures_immutable()186 public final void testGetFailures_immutable() throws Exception { 187 List<F> failures = mCallback.getFailures(); 188 expect.withMessage("%s.getFailures() initially", mCallback).that(failures).isEmpty(); 189 190 assertThrows(UnsupportedOperationException.class, () -> failures.add(newFailure())); 191 192 expect.withMessage("%s.getFailures() after", mCallback) 193 .that(mCallback.getFailures()) 194 .isEmpty(); 195 } 196 197 @Test testToString_containsFailures()198 public final void testToString_containsFailures() throws Exception { 199 // Initial state 200 String toString = mCallback.toString(); 201 expect.withMessage("toString() initially").that(toString).contains("(no failure yet)"); 202 203 // NOTE: failures are shown as "results" - see why on 204 // FailableResultSyncCallback.customizeToString() 205 206 // 1st call 207 F firstFailure = newFailure(); 208 mCallback.injectFailure(firstFailure); 209 toString = mCallback.toString(); 210 expect.withMessage("toString() after 1st call") 211 .that(toString) 212 .contains("result=" + firstFailure); 213 expect.withMessage("toString() after 1st call") 214 .that(toString) 215 .contains("results=[" + firstFailure + "]"); 216 217 // 2nd call 218 F secondFailure = newFailure(); 219 mCallback.injectFailure(secondFailure); 220 toString = mCallback.toString(); 221 expect.withMessage("toString() after 2nd call") 222 .that(toString) 223 .contains("result=" + firstFailure); 224 expect.withMessage("toString() after 2nd call") 225 .that(toString) 226 .contains("results=[" + firstFailure + ", " + secondFailure + "]"); 227 } 228 assertGetFailureMethodsWhenNoFailure(CB callback, String when)229 protected final void assertGetFailureMethodsWhenNoFailure(CB callback, String when) { 230 expect.withMessage("%s.getFailure() %s", callback, when) 231 .that(callback.getFailure()) 232 .isNull(); 233 expect.withMessage("%s.getFailures() %s", callback, when) 234 .that(callback.getFailures()) 235 .isEmpty(); 236 } 237 238 @SafeVarargs assertGetFailureMethods( CB callback, String when, @Nullable F... failures)239 protected final void assertGetFailureMethods( 240 CB callback, String when, @Nullable F... failures) { 241 expect.withMessage("%s.getFailure() %s", callback, when) 242 .that(callback.getFailure()) 243 .isSameInstanceAs(failures[0]); 244 expect.withMessage("%s.getFailures() %s", callback, when) 245 .that(callback.getFailures()) 246 .containsExactly(failures) 247 .inOrder(); 248 } 249 250 @SafeVarargs assertGetFailureMethodsWhenInjectedResultWasCalledFirst( CB callback, String when, @Nullable F... failures)251 protected final void assertGetFailureMethodsWhenInjectedResultWasCalledFirst( 252 CB callback, String when, @Nullable F... failures) { 253 expect.withMessage("%s.getFailure() %s", callback, when) 254 .that(callback.getFailure()) 255 .isNull(); 256 expect.withMessage("%s.getFailures() %s", callback, when) 257 .that(callback.getFailures()) 258 .containsExactly(failures) 259 .inOrder(); 260 } 261 262 @SafeVarargs assertGetResultMethodsWhenInjectFailureWasCalledFirst( CB callback, String when, @Nullable R... expectedResults)263 protected final void assertGetResultMethodsWhenInjectFailureWasCalledFirst( 264 CB callback, String when, @Nullable R... expectedResults) { 265 expect.withMessage("%s.getResult() %s", callback, when).that(callback.getResult()).isNull(); 266 expect.withMessage("%s.getResults() %s", callback, when) 267 .that(callback.getResults()) 268 .containsExactly(expectedResults) 269 .inOrder(); 270 } 271 assertInitialState(CB callback)272 private void assertInitialState(CB callback) { 273 assertGetResultMethodsWhenNoResult(callback, "initially"); 274 assertGetFailureMethodsWhenNoFailure(callback, "initially"); 275 } 276 } 277