Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 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.tradefed.util; |
| 18 | |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 19 | import com.android.tradefed.build.BuildRetrievalError; |
| 20 | |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 21 | import com.google.cloud.storage.Blob; |
| 22 | import com.google.cloud.storage.Bucket; |
| 23 | import com.google.cloud.storage.Storage.BlobListOption; |
| 24 | |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 25 | import org.junit.After; |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 26 | import org.junit.Assert; |
| 27 | import org.junit.Before; |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 28 | import org.junit.Test; |
| 29 | import org.junit.runner.RunWith; |
| 30 | import org.junit.runners.JUnit4; |
| 31 | |
| 32 | import java.io.File; |
| 33 | import java.io.IOException; |
| 34 | import java.io.InputStream; |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 35 | import java.nio.file.Paths; |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 36 | |
| 37 | /** {@link GCSFileDownloader} functional test. */ |
| 38 | @RunWith(JUnit4.class) |
| 39 | public class GCSFileDownloaderFuncTest { |
| 40 | |
Xing Dai | ac1b0b0 | 2018-07-11 15:07:38 -0700 | [diff] [blame] | 41 | private static final String BUCKET_NAME = "tradefed_function_test"; |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 42 | private static final String FILE_NAME1 = "a_host_config.xml"; |
| 43 | private static final String FILE_NAME2 = "file2.txt"; |
| 44 | private static final String FILE_NAME3 = "file3.txt"; |
| 45 | private static final String FILE_NAME4 = "file4.txt"; |
| 46 | private static final String FOLDER_NAME1 = "folder1"; |
| 47 | private static final String FOLDER_NAME2 = "folder2"; |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 48 | private static final String FILE_CONTENT = "Hello World!"; |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 49 | |
| 50 | private GCSFileDownloader mDownloader; |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 51 | private Bucket mBucket; |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 52 | private String mRemoteRoot; |
| 53 | private File mLocalRoot; |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 54 | |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 55 | private static void createFile(String content, Bucket bucket, String... pathSegs) { |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 56 | String path = String.join("/", pathSegs); |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 57 | bucket.create(path, content.getBytes()); |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | @Before |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 61 | public void setUp() throws IOException { |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 62 | File tempFile = |
| 63 | FileUtil.createTempFile(GCSFileDownloaderFuncTest.class.getSimpleName(), ""); |
| 64 | mRemoteRoot = tempFile.getName(); |
| 65 | FileUtil.deleteFile(tempFile); |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 66 | mDownloader = |
| 67 | new GCSFileDownloader() { |
| 68 | |
| 69 | @Override |
| 70 | File createTempFile(String remoteFilePath, File rootDir) |
| 71 | throws BuildRetrievalError { |
| 72 | try { |
| 73 | File tmpFile = |
| 74 | FileUtil.createTempFileForRemote(remoteFilePath, mLocalRoot); |
| 75 | tmpFile.delete(); |
| 76 | return tmpFile; |
| 77 | } catch (IOException e) { |
| 78 | throw new BuildRetrievalError(e.getMessage(), e); |
| 79 | } |
| 80 | } |
| 81 | }; |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 82 | mBucket = mDownloader.getStorage().get(BUCKET_NAME); |
| 83 | createFile(FILE_CONTENT, mBucket, mRemoteRoot, FILE_NAME1); |
| 84 | createFile(FILE_NAME2, mBucket, mRemoteRoot, FOLDER_NAME1, FILE_NAME2); |
| 85 | createFile(FILE_NAME3, mBucket, mRemoteRoot, FOLDER_NAME1, FILE_NAME3); |
| 86 | createFile(FILE_NAME4, mBucket, mRemoteRoot, FOLDER_NAME1, FOLDER_NAME2, FILE_NAME4); |
| 87 | mLocalRoot = FileUtil.createTempDir(GCSFileDownloaderFuncTest.class.getSimpleName()); |
| 88 | |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 89 | } |
| 90 | |
| 91 | @After |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 92 | public void tearDown() { |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 93 | FileUtil.recursiveDelete(mLocalRoot); |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 94 | for (Blob blob : mBucket.list(BlobListOption.prefix(mRemoteRoot)).iterateAll()) { |
| 95 | blob.delete(); |
| 96 | } |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 97 | } |
| 98 | |
| 99 | @Test |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 100 | public void testDownloadFile_streamOutput() throws Exception { |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 101 | InputStream inputStream = |
| 102 | mDownloader.downloadFile(BUCKET_NAME, mRemoteRoot + "/" + FILE_NAME1); |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 103 | String content = StreamUtil.getStringFromStream(inputStream); |
| 104 | Assert.assertEquals(FILE_CONTENT, content); |
| 105 | } |
| 106 | |
| 107 | @Test |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 108 | public void testDownloadFile_streamOutput_notExist() throws Exception { |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 109 | try { |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 110 | mDownloader.downloadFile(BUCKET_NAME, mRemoteRoot + "/" + "non_exist_file"); |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 111 | Assert.fail("Should throw IOExcepiton."); |
| 112 | } catch (IOException e) { |
| 113 | // Expect IOException |
| 114 | } |
| 115 | } |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 116 | |
| 117 | @Test |
| 118 | public void testDownloadFile() throws Exception { |
| 119 | File localFile = |
| 120 | mDownloader.downloadFile( |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 121 | String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1)); |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 122 | String content = FileUtil.readStringFromFile(localFile); |
| 123 | Assert.assertEquals(FILE_CONTENT, content); |
| 124 | } |
| 125 | |
| 126 | @Test |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 127 | public void testDownloadFile_nonExist() throws Exception { |
| 128 | try { |
| 129 | mDownloader.downloadFile( |
| 130 | String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, "non_exist_file")); |
| 131 | Assert.fail("Should throw BuildRetrievalError."); |
| 132 | } catch (BuildRetrievalError e) { |
| 133 | // Expect BuildRetrievalError |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | @Test |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 138 | public void testDownloadFile_folder() throws Exception { |
| 139 | File localFile = |
| 140 | mDownloader.downloadFile( |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 141 | String.format("gs://%s/%s/%s/", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1)); |
| 142 | checkDownloadedFolder(localFile); |
| 143 | } |
| 144 | |
| 145 | @Test |
| 146 | public void testDownloadFile_folderNotsanitize() throws Exception { |
| 147 | File localFile = |
| 148 | mDownloader.downloadFile( |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 149 | String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1)); |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 150 | checkDownloadedFolder(localFile); |
| 151 | } |
| 152 | |
| 153 | private void checkDownloadedFolder(File localFile) throws Exception { |
xingdai | 1adb0d0 | 2018-08-01 21:20:18 -0700 | [diff] [blame] | 154 | Assert.assertTrue(localFile.isDirectory()); |
| 155 | Assert.assertEquals(3, localFile.list().length); |
| 156 | for (String filename : localFile.list()) { |
| 157 | if (filename.equals(FILE_NAME2)) { |
| 158 | Assert.assertEquals( |
| 159 | FILE_NAME2, |
| 160 | FileUtil.readStringFromFile( |
| 161 | new File(localFile.getAbsolutePath(), filename))); |
| 162 | } else if (filename.equals(FILE_NAME3)) { |
| 163 | Assert.assertEquals( |
| 164 | FILE_NAME3, |
| 165 | FileUtil.readStringFromFile( |
| 166 | new File(localFile.getAbsolutePath(), filename))); |
| 167 | } else if (filename.equals(FOLDER_NAME2)) { |
| 168 | File subFolder = new File(localFile.getAbsolutePath(), filename); |
| 169 | Assert.assertTrue(subFolder.isDirectory()); |
| 170 | Assert.assertEquals(1, subFolder.list().length); |
| 171 | Assert.assertEquals( |
| 172 | FILE_NAME4, |
| 173 | FileUtil.readStringFromFile( |
| 174 | new File(subFolder.getAbsolutePath(), subFolder.list()[0]))); |
| 175 | } else { |
| 176 | Assert.assertTrue(String.format("Unknonwn file %s", filename), false); |
| 177 | } |
| 178 | } |
| 179 | } |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 180 | |
| 181 | @Test |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 182 | public void testDownloadFile_folder_nonExist() throws Exception { |
| 183 | try { |
| 184 | mDownloader.downloadFile( |
| 185 | String.format("gs://%s/%s/%s/", BUCKET_NAME, "mRemoteRoot", "nonExistFolder")); |
| 186 | Assert.fail("Should throw BuildRetrievalError."); |
| 187 | } catch (BuildRetrievalError e) { |
| 188 | // Expect BuildRetrievalError |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | @Test |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 193 | public void testCheckFreshness() throws Exception { |
| 194 | String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1); |
| 195 | File localFile = mDownloader.downloadFile(remotePath); |
| 196 | Assert.assertTrue(mDownloader.isFresh(localFile, remotePath)); |
| 197 | } |
| 198 | |
| 199 | @Test |
| 200 | public void testCheckFreshness_notFresh() throws Exception { |
| 201 | String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FILE_NAME1); |
| 202 | File localFile = mDownloader.downloadFile(remotePath); |
| 203 | // Change the remote file. |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 204 | createFile("New content.", mBucket, mRemoteRoot, FILE_NAME1); |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 205 | Assert.assertFalse(mDownloader.isFresh(localFile, remotePath)); |
| 206 | } |
| 207 | |
| 208 | @Test |
| 209 | public void testCheckFreshness_folder() throws Exception { |
| 210 | String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1); |
| 211 | File localFolder = mDownloader.downloadFile(remotePath); |
| 212 | Assert.assertTrue(mDownloader.isFresh(localFolder, remotePath)); |
| 213 | } |
| 214 | |
| 215 | @Test |
| 216 | public void testCheckFreshness_folder_addFile() throws Exception { |
| 217 | String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1); |
| 218 | File localFolder = mDownloader.downloadFile(remotePath); |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 219 | createFile("A new file", mBucket, mRemoteRoot, FOLDER_NAME1, FOLDER_NAME2, "new_file.txt"); |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 220 | Assert.assertFalse(mDownloader.isFresh(localFolder, remotePath)); |
| 221 | } |
| 222 | |
| 223 | @Test |
| 224 | public void testCheckFreshness_folder_removeFile() throws Exception { |
| 225 | String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1); |
| 226 | File localFolder = mDownloader.downloadFile(remotePath); |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 227 | mBucket.get(Paths.get(mRemoteRoot, FOLDER_NAME1, FILE_NAME3).toString()).delete(); |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 228 | Assert.assertFalse(mDownloader.isFresh(localFolder, remotePath)); |
| 229 | } |
| 230 | |
| 231 | @Test |
| 232 | public void testCheckFreshness_folder_changeFile() throws Exception { |
| 233 | String remotePath = String.format("gs://%s/%s/%s", BUCKET_NAME, mRemoteRoot, FOLDER_NAME1); |
| 234 | File localFolder = mDownloader.downloadFile(remotePath); |
Xing Dai | 842a176 | 2019-01-02 12:13:10 -0800 | [diff] [blame^] | 235 | createFile("New content", mBucket, mRemoteRoot, FOLDER_NAME1, FILE_NAME3); |
xingdai | 1432ffe | 2018-08-24 14:44:11 -0700 | [diff] [blame] | 236 | Assert.assertFalse(mDownloader.isFresh(localFolder, remotePath)); |
| 237 | } |
Xing Dai | 77a6017 | 2017-12-19 18:07:09 -0800 | [diff] [blame] | 238 | } |