blob: 79bbdbbc8594d79288f83a92d75b0750112764dc [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Tests for {@link android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager}
*
* atest CtsWallpaperEffectsGenerationServiceTestCases
*/
package android.wallpapereffectsgeneration.cts;
import static androidx.test.InstrumentationRegistry.getContext;
import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import android.app.wallpapereffectsgeneration.CinematicEffectRequest;
import android.app.wallpapereffectsgeneration.CinematicEffectResponse;
import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager;
import android.app.wallpapereffectsgeneration.WallpaperEffectsGenerationManager.CinematicEffectListener;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Process;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.RequiredServiceRule;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Tests for {@link WallpaperEffectsGenerationManager}
*
* atest CtsWallpaperEffectsGenerationServiceTestCases
*/
@RunWith(AndroidJUnit4.class)
public class WallpaperEffectsGenerationManagerTest {
private static final String TAG = "WallpaperEffectsGenerationTest";
private static final boolean DEBUG = false;
private static final long VERIFY_TIMEOUT_MS = 5_000;
private static final long SERVICE_LIFECYCLE_TIMEOUT_MS = 20_000;
@Rule
public final RequiredServiceRule mRequiredServiceRule =
new RequiredServiceRule(Context.WALLPAPER_EFFECTS_GENERATION_SERVICE);
private WallpaperEffectsGenerationManager mManager;
private CtsWallpaperEffectsGenerationService.Watcher mWatcher;
private CinematicEffectRequest mInitialTaskRequest =
createCinematicEffectRequest("initial-task");
@Before
public void setup() throws Exception {
mWatcher = CtsWallpaperEffectsGenerationService.setWatcher();
mManager = getContext().getSystemService(WallpaperEffectsGenerationManager.class);
setService(CtsWallpaperEffectsGenerationService.SERVICE_NAME);
// The wallpaper effects generation services are created lazily,
// call one method to start the service for these tests.
mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
reset(mWatcher.verifier);
mManager.generateCinematicEffect(mInitialTaskRequest,
Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
await(mWatcher.created, "Waiting for onCreated()");
}
@After
public void tearDown() throws Exception {
setService(null);
await(mWatcher.destroyed, "Waiting for onDestroyed()");
mWatcher = null;
CtsWallpaperEffectsGenerationService.clearWatcher();
}
@Test
public void testWallpaperEffectsGenerationServiceConnection() {
// In test setup, 1st request is already made.
assertNotNull(mManager);
// Check the 1st call in setup was received by service.
await(mWatcher.requested, "Waiting for requested.");
await(mWatcher.initialCallReturned, "Result is produced");
// Check the request the server received is the request sent.
verifyService().onGenerateCinematicEffect(eq(mInitialTaskRequest));
}
@Test
public void testGenerateCinematicEffect_okResponse() {
mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
reset(mWatcher.verifier);
assertNotNull(mManager);
// Let the initial request in setup finishes.
await(mWatcher.requested, "Waiting for connect call finishes.");
CinematicEffectRequest request = createSimpleCinematicEffectRequest("ok-task");
mManager.generateCinematicEffect(request, Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
await(mWatcher.okResponse, "Result is okay");
verifyService().onGenerateCinematicEffect(eq(request));
}
@Test
public void testGenerateCinematicEffect_errorResponse() {
mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
reset(mWatcher.verifier);
assertNotNull(mManager);
// Let the initial request in setup finishes.
await(mWatcher.initialCallReturned, "Waiting for connect call finishes.");
CinematicEffectRequest request = createSimpleCinematicEffectRequest("error-task");
mManager.generateCinematicEffect(request, Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
await(mWatcher.errorResponse, "Result is error");
verifyService().onGenerateCinematicEffect(eq(request));
}
@Test
public void testGenerateCinematicEffect_pendingResponse() {
mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
reset(mWatcher.verifier);
assertNotNull(mManager);
// Let the initial request in setup finishes.
await(mWatcher.initialCallReturned, "Waiting for requested call finishes.");
CinematicEffectRequest request1 = createCinematicEffectRequest("pending-task-id");
CinematicEffectRequest request2 = createCinematicEffectRequest("pending-task-id");
mManager.generateCinematicEffect(request1, Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
mManager.generateCinematicEffect(request2, Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
await(mWatcher.pendingResponse, "Second request immediately fail with pending response");
}
@Test
public void testGenerateCinematicEffect_tooManyRequestsResponse() {
mWatcher.verifier = Mockito.mock(CtsWallpaperEffectsGenerationService.class);
reset(mWatcher.verifier);
assertNotNull(mManager);
// Let the initial request in setup finishes.
await(mWatcher.initialCallReturned, "Waiting for connect call finishes.");
CinematicEffectRequest request1 = createCinematicEffectRequest("pending-task-id");
CinematicEffectRequest request2 = createCinematicEffectRequest("other-task-id");
mManager.generateCinematicEffect(request1, Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
mManager.generateCinematicEffect(request2, Executors.newSingleThreadExecutor(),
createCinematicEffectListener());
await(mWatcher.tooManyRequestsResponse,
"Second request immediately fail with too many requests response");
}
private CinematicEffectListener createCinematicEffectListener() {
return cinematicEffectResponse -> {
Log.d(TAG, "cinematic effect response taskId = " + cinematicEffectResponse.getTaskId()
+ ", status code = " + cinematicEffectResponse.getStatusCode());
if (cinematicEffectResponse.getStatusCode()
== CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_OK) {
mWatcher.okResponse.countDown();
} else if (cinematicEffectResponse.getStatusCode()
== CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_PENDING) {
mWatcher.pendingResponse.countDown();
} else if (cinematicEffectResponse.getStatusCode()
== CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_TOO_MANY_REQUESTS) {
mWatcher.tooManyRequestsResponse.countDown();
} else if (cinematicEffectResponse.getStatusCode()
== CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_NOT_READY) {
// This case is used to check the 1st request in the "Setup" method finishes.
mWatcher.initialCallReturned.countDown();
} else if (cinematicEffectResponse.getStatusCode()
== CinematicEffectResponse.CINEMATIC_EFFECT_STATUS_ERROR) {
mWatcher.errorResponse.countDown();
}
};
}
private CinematicEffectRequest createCinematicEffectRequest(String taskId) {
Bitmap bmp = Bitmap.createBitmap(32, 48, Bitmap.Config.ARGB_8888);
return new CinematicEffectRequest(taskId, bmp);
}
private CtsWallpaperEffectsGenerationService verifyService() {
return verify(mWatcher.verifier, timeout(VERIFY_TIMEOUT_MS));
}
private void setService(String service) {
if (DEBUG) {
Log.d(TAG, "Setting WallpaperEffectsGeneration service to " + service);
}
int userId = Process.myUserHandle().getIdentifier();
String shellCommand = "";
if (service != null) {
shellCommand = "cmd wallpaper_effects_generation set temporary-service "
+ userId + " " + service + " 60000";
} else {
shellCommand = "cmd wallpaper_effects_generation set temporary-service " + userId;
}
if (DEBUG) {
Log.d(TAG, "runShellCommand(): " + shellCommand);
}
runShellCommand(shellCommand);
}
private void await(@NonNull CountDownLatch latch, @NonNull String message) {
try {
assertWithMessage(message).that(
latch.await(SERVICE_LIFECYCLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while: " + message);
}
}
private CinematicEffectRequest createSimpleCinematicEffectRequest(String taskId) {
return new CinematicEffectRequest(taskId,
Bitmap.createBitmap(32, 48, Bitmap.Config.ARGB_8888));
}
}