blob: 77086f0d356a071d13a34fcb3c0e6b1a55d4a606 [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.
*/
package android.scopedstorage.cts.host;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AppModeFull;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import com.android.tradefed.util.CommandResult;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
@RunWith(DeviceJUnit4ClassRunner.class)
@AppModeFull
public class AppCloningMediaProviderHostTest extends BaseHostTestCase{
protected static final String DEVICE_TEST_APP_PACKAGE = "android.scopedstorage.cts";
protected static final String DEVICE_TEST_APP = "AppCloningDeviceTest.apk";
private static final String DEVICE_TEST_CLASS = DEVICE_TEST_APP_PACKAGE
+ ".AppCloningDeviceTest";
// This app performs the File Creation and Read operations from the Device.
protected static final String SCOPED_STORAGE_TEST_APP_B_APK = "CtsScopedStorageTestAppB.apk";
private static final int CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS = 20000;
private static final long DEFAULT_INSTRUMENTATION_TIMEOUT_MS = 600_000;
private static final String EXTERNAL_STORAGE_PATH = "/storage/emulated/%d/";
private static final String CURRENT_USER_ID = "currentUserId";
private static final String FILE_TO_BE_CREATED = "fileToBeCreated";
private static final String FILE_EXPECTED_TO_BE_PRESENT = "fileExpectedToBePresent";
private static final String FILE_NOT_EXPECTED_TO_BE_PRESENT = "fileNotExpectedToBePresent";
/**
* Provide different name to Files being created, on each execution of the test, so that
* flakiness from previously existing files can be avoided.
*/
private static final String NONCE = String.valueOf(System.nanoTime());
private static String sCloneUserId;
@BeforeClassWithInfo
public static void beforeClassWithDevice(TestInformation testInfo) throws Exception {
final ITestDevice sDevice = testInfo.getDevice();
assertThat(sDevice).isNotNull();
setDevice(sDevice);
assumeTrue("Device doesn't support multiple users", supportsMultipleUsers());
assumeFalse("Device is in headless system user mode", isHeadlessSystemUserMode());
assumeTrue(isAtLeastS());
assumeFalse("Device uses sdcardfs", usesSdcardFs());
// create clone user
String output = sDevice.executeShellCommand(
"pm create-user --profileOf 0 --user-type android.os.usertype.profile.CLONE "
+ "testUser");
sCloneUserId = output.substring(output.lastIndexOf(' ') + 1).replaceAll("[^0-9]",
"");
assertThat(sCloneUserId).isNotEmpty();
// start clone user
CommandResult out = sDevice.executeShellV2Command("am start-user -w " + sCloneUserId);
assertThat(isSuccessful(out)).isTrue();
Integer mCloneUserIdInt = Integer.parseInt(sCloneUserId);
String sCloneUserStoragePath = String.format(EXTERNAL_STORAGE_PATH,
Integer.parseInt(sCloneUserId));
// Check that the clone user directories have been created
eventually(() -> sDevice.doesFileExist(sCloneUserStoragePath, mCloneUserIdInt),
CLONE_PROFILE_DIRECTORY_CREATION_TIMEOUT_MS);
}
@AfterClassWithInfo
public static void afterClass(TestInformation testInfo) throws Exception {
if (!supportsMultipleUsers() || isHeadlessSystemUserMode() || !isAtLeastS()
|| usesSdcardFs()) return;
testInfo.getDevice().executeShellCommand("pm remove-user " + sCloneUserId);
}
@Test
public void testGetFilesInDirectoryViaMediaProvider() throws Exception {
// Install the Device Test App in both the user spaces.
installPackage(DEVICE_TEST_APP, "--user all");
// Install the Scoped Storage Test App in both the user spaces.
installPackage(SCOPED_STORAGE_TEST_APP_B_APK, "--user all");
int currentUserId = getCurrentUserId();
final String fileName = "tmpFileToPush" + NONCE + ".png";
// We add the file in DCIM directory of User 0.
Map<String, String> ownerArgs = new HashMap<>();
ownerArgs.put(CURRENT_USER_ID, String.valueOf(currentUserId));
ownerArgs.put(FILE_TO_BE_CREATED, fileName);
runDeviceTestAsUserInPkgA("testInsertFilesInDirectoryViaMediaProvider",
currentUserId, ownerArgs);
// We add the file in DCIM directory of Cloned User.
final String fileNameClonedUser = "tmpFileToPushClonedUser" + NONCE + ".png";
Map<String, String> cloneArgs = new HashMap<>();
cloneArgs.put(CURRENT_USER_ID, sCloneUserId);
cloneArgs.put(FILE_TO_BE_CREATED, fileNameClonedUser);
runDeviceTestAsUserInPkgA("testInsertFilesInDirectoryViaMediaProvider",
Integer.parseInt(sCloneUserId), cloneArgs);
// Querying as user 0 should enlist the file(s) created by user 0 only.
Map<String, String> listFilesArgs = new HashMap<>();
listFilesArgs.put(CURRENT_USER_ID, String.valueOf(currentUserId));
listFilesArgs.put(FILE_EXPECTED_TO_BE_PRESENT, fileName);
listFilesArgs.put(FILE_NOT_EXPECTED_TO_BE_PRESENT, fileNameClonedUser);
runDeviceTestAsUserInPkgA("testGetFilesInDirectoryViaMediaProviderRespectsUserId",
currentUserId, listFilesArgs);
// Querying as cloned user should enlist the file(s) created by cloned user only.
listFilesArgs.put(CURRENT_USER_ID, sCloneUserId);
listFilesArgs.put(FILE_EXPECTED_TO_BE_PRESENT, fileNameClonedUser);
listFilesArgs.put(FILE_NOT_EXPECTED_TO_BE_PRESENT, fileName);
runDeviceTestAsUserInPkgA("testGetFilesInDirectoryViaMediaProviderRespectsUserId",
Integer.parseInt(sCloneUserId), listFilesArgs);
}
protected void runDeviceTestAsUserInPkgA(@Nonnull String testMethod, int userId,
@Nonnull Map<String, String> args) throws Exception {
DeviceTestRunOptions deviceTestRunOptions =
new DeviceTestRunOptions(DEVICE_TEST_APP_PACKAGE)
.setDevice(getDevice())
.setTestClassName(DEVICE_TEST_CLASS)
.setTestMethodName(testMethod)
.setMaxInstrumentationTimeoutMs(DEFAULT_INSTRUMENTATION_TIMEOUT_MS)
.setUserId(userId);
for (Map.Entry<String, String> entry : args.entrySet()) {
deviceTestRunOptions.addInstrumentationArg(entry.getKey(), entry.getValue());
}
assertWithMessage(testMethod + " failed").that(
runDeviceTests(deviceTestRunOptions)).isTrue();
}
}