blob: 8d97efb712a11603c1b38535afd699df5233e1c1 [file] [log] [blame]
/*
* Copyright (C) 2018 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 com.android.tradefed.util;
import com.android.tradefed.build.BuildRetrievalError;
import com.google.api.client.googleapis.batch.BatchCallback;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.InputStreamContent;
import com.google.api.services.storage.Storage;
import com.google.api.services.storage.Storage.Objects.List;
import com.google.api.services.storage.model.Objects;
import com.google.api.services.storage.model.StorageObject;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.Collections;
/** {@link GCSFileDownloader} functional test. */
@RunWith(JUnit4.class)
public class GCSFileDownloaderFuncTest {
private static final String BUCKET_NAME = "tradefed_function_test";
private static final String FILE_NAME1 = "a_host_config.xml";
private static final String FILE_NAME2 = "file2.txt";
private static final String FILE_NAME3 = "file3.txt";
private static final String FILE_NAME4 = "file4.txt";
private static final String FOLDER_NAME1 = "folder1";
private static final String FOLDER_NAME2 = "folder2";
private static final String FILE_CONTENT = "Hello World!";
private GCSFileDownloader mDownloader;
private String mRemoteRoot;
private File mLocalRoot;
private Storage mStorage;
private static void createFile(
Storage storage, String content, String bucketName, String... pathSegs)
throws IOException {
String path = String.join("/", pathSegs);
StorageObject object = new StorageObject();
object.setName(path);
storage.objects()
.insert(
bucketName,
object,
new InputStreamContent(null, new ByteArrayInputStream(content.getBytes())))
.execute();
}
@Before
public void setUp() throws IOException {
File tempFile =
FileUtil.createTempFile(GCSFileDownloaderFuncTest.class.getSimpleName(), "");
mRemoteRoot = tempFile.getName();
FileUtil.deleteFile(tempFile);
mDownloader =
new GCSFileDownloader() {
@Override
File createTempFile(String remoteFilePath, File rootDir)
throws BuildRetrievalError {
try {
File tmpFile =
FileUtil.createTempFileForRemote(remoteFilePath, mLocalRoot);
tmpFile.delete();
return tmpFile;
} catch (IOException e) {
throw new BuildRetrievalError(e.getMessage(), e);
}
}
};
mStorage =
mDownloader.getStorage(
Collections.singleton(
"https://www.googleapis.com/auth/devstorage.read_write"));
createFile(mStorage, FILE_CONTENT, BUCKET_NAME, mRemoteRoot, FILE_NAME1);
createFile(mStorage, FILE_NAME2, BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FILE_NAME2);
createFile(mStorage, FILE_NAME3, BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FILE_NAME3);
// Create a special case condition where folder name is also a file name.
createFile(mStorage, FILE_NAME3, BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FOLDER_NAME2);
createFile(
mStorage,
FILE_NAME4,
BUCKET_NAME,
mRemoteRoot,
FOLDER_NAME1,
FOLDER_NAME2,
FILE_NAME4);
mLocalRoot = FileUtil.createTempDir(GCSFileDownloaderFuncTest.class.getSimpleName());
}
@After
public void tearDown() throws IOException {
FileUtil.recursiveDelete(mLocalRoot);
String pageToken = null;
BatchRequest batchRequest = mStorage.batch();
while (true) {
List listOperation = mStorage.objects().list(BUCKET_NAME).setPrefix(mRemoteRoot);
if (pageToken == null) {
listOperation.setPageToken(pageToken);
}
Objects objects = listOperation.execute();
for (StorageObject object : objects.getItems()) {
batchRequest.queue(
mStorage.objects().delete(BUCKET_NAME, object.getName()).buildHttpRequest(),
Void.class,
IOException.class,
new BatchCallback<Void, IOException>() {
@Override
public void onSuccess(Void arg0, HttpHeaders arg1) throws IOException {}
@Override
public void onFailure(IOException e, HttpHeaders arg1)
throws IOException {
throw e;
}
});
}
pageToken = objects.getNextPageToken();
if (pageToken == null) {
batchRequest.execute();
return;
}
}
}
@Test
public void testDownloadFile_streamOutput() throws Exception {
InputStream inputStream =
mDownloader.downloadFile(BUCKET_NAME, mRemoteRoot + "/" + FILE_NAME1);
String content = StreamUtil.getStringFromStream(inputStream);
Assert.assertEquals(FILE_CONTENT, content);
inputStream.reset();
}
@Test
public void testDownloadFile_streamOutput_notExist() throws Exception {
try {
mDownloader.downloadFile(BUCKET_NAME, mRemoteRoot + "/" + "non_exist_file");
Assert.fail("Should throw IOException.");
} catch (IOException e) {
// Expect IOException
}
}
@Test
public void testGetRemoteFileMetaData() throws Exception {
String filename = mRemoteRoot + "/" + FILE_NAME1;
StorageObject object = mDownloader.getRemoteFileMetaData(BUCKET_NAME, filename);
Assert.assertEquals(filename, object.getName());
}
@Test
public void testGetRemoteFileMetaData_notExist() throws Exception {
String filename = mRemoteRoot + "/" + "not_exist";
StorageObject object = mDownloader.getRemoteFileMetaData(BUCKET_NAME, filename);
Assert.assertNull(object);
}
@Test
public void testIsRemoteFolder() throws Exception {
Assert.assertFalse(
mDownloader.isRemoteFolder(
BUCKET_NAME, Paths.get(mRemoteRoot, FILE_NAME1).toString()));
Assert.assertTrue(
mDownloader.isRemoteFolder(
BUCKET_NAME, Paths.get(mRemoteRoot, FOLDER_NAME1).toString()));
}
@Test
public void testDownloadFile() throws Exception {
File localFile =
mDownloader.downloadFile(
String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1));
String content = FileUtil.readStringFromFile(localFile);
Assert.assertEquals(FILE_CONTENT, content);
}
@Test
public void testDownloadFile_nonExist() throws Exception {
try {
mDownloader.downloadFile(
String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, "non_exist_file"));
Assert.fail("Should throw BuildRetrievalError.");
} catch (BuildRetrievalError e) {
// Expect BuildRetrievalError
}
}
@Test
public void testDownloadFile_folder() throws Exception {
File localFile =
mDownloader.downloadFile(
String.format("gs://%s/%s/%s/", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1));
checkDownloadedFolder(localFile);
}
@Test
public void testDownloadFile_folderNotsanitize() throws Exception {
File localFile =
mDownloader.downloadFile(
String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1));
checkDownloadedFolder(localFile);
}
private void checkDownloadedFolder(File localFile) throws Exception {
Assert.assertTrue(localFile.isDirectory());
Assert.assertEquals(4, localFile.list().length);
for (String filename : localFile.list()) {
if (filename.equals(FILE_NAME2)) {
Assert.assertEquals(
FILE_NAME2,
FileUtil.readStringFromFile(
new File(localFile.getAbsolutePath(), filename)));
} else if (filename.equals(FILE_NAME3)) {
Assert.assertEquals(
FILE_NAME3,
FileUtil.readStringFromFile(
new File(localFile.getAbsolutePath(), filename)));
} else if (filename.equals(FOLDER_NAME2 + "_folder")) {
File subFolder = new File(localFile.getAbsolutePath(), filename);
Assert.assertTrue(subFolder.isDirectory());
Assert.assertEquals(1, subFolder.list().length);
Assert.assertEquals(
FILE_NAME4,
FileUtil.readStringFromFile(
new File(subFolder.getAbsolutePath(), subFolder.list()[0])));
} else if (filename.equals(FOLDER_NAME2)) {
File fileWithFolderName = new File(localFile.getAbsolutePath(), filename);
Assert.assertTrue(fileWithFolderName.isFile());
} else {
Assert.assertTrue(String.format("Unknonwn file %s", filename), false);
}
}
}
@Test
public void testDownloadFile_folder_nonExist() throws Exception {
try {
mDownloader.downloadFile(
String.format("gs://%s/%s/%s/", BUCKET_NAME, "mRemoteRoot", "nonExistFolder"));
Assert.fail("Should throw BuildRetrievalError.");
} catch (BuildRetrievalError e) {
// Expect BuildRetrievalError
}
}
@Test
public void testCheckFreshness() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1);
File localFile = mDownloader.downloadFile(remotePath);
Assert.assertTrue(mDownloader.isFresh(localFile, remotePath));
}
@Test
public void testCheckFreshness_notExist() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1);
Assert.assertFalse(mDownloader.isFresh(new File("/not/exist"), remotePath));
}
@Test
public void testCheckFreshness_folderNotExist() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1);
Assert.assertFalse(mDownloader.isFresh(new File("/not/exist"), remotePath));
}
@Test
public void testCheckFreshness_remoteNotExist() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1);
String remoteNotExistPath = String.format("gs://%s/%s/no_exist", BUCKET_NAME, mRemoteRoot);
File localFile = mDownloader.downloadFile(remotePath);
Assert.assertFalse(mDownloader.isFresh(localFile, remoteNotExistPath));
}
@Test
public void testCheckFreshness_remoteFolderNotExist() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1);
String remoteNotExistPath = String.format("gs://%s/%s/no_exist/", BUCKET_NAME, mRemoteRoot);
File localFolder = mDownloader.downloadFile(remotePath);
Assert.assertFalse(mDownloader.isFresh(localFolder, remoteNotExistPath));
}
@Test
public void testCheckFreshness_notFresh() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1);
File localFile = mDownloader.downloadFile(remotePath);
// Change the remote file.
createFile(mStorage, "New content.", BUCKET_NAME, mRemoteRoot, FILE_NAME1);
Assert.assertFalse(mDownloader.isFresh(localFile, remotePath));
}
@Test
public void testCheckFreshness_folder() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1);
File localFolder = mDownloader.downloadFile(remotePath);
Assert.assertTrue(mDownloader.isFresh(localFolder, remotePath));
}
@Test
public void testCheckFreshness_folder_addFile() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1);
File localFolder = mDownloader.downloadFile(remotePath);
createFile(
mStorage,
"A new file",
BUCKET_NAME,
mRemoteRoot,
FOLDER_NAME1,
FOLDER_NAME2,
"new_file.txt");
Assert.assertFalse(mDownloader.isFresh(localFolder, remotePath));
}
@Test
public void testCheckFreshness_folder_removeFile() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1);
File localFolder = mDownloader.downloadFile(remotePath);
mStorage.objects()
.delete(BUCKET_NAME, Paths.get(mRemoteRoot, FOLDER_NAME1, FILE_NAME3).toString())
.execute();
Assert.assertFalse(mDownloader.isFresh(localFolder, remotePath));
}
@Test
public void testCheckFreshness_folder_changeFile() throws Exception {
String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1);
File localFolder = mDownloader.downloadFile(remotePath);
createFile(mStorage, "New content", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1, FILE_NAME3);
Assert.assertFalse(mDownloader.isFresh(localFolder, remotePath));
}
}