1 /* 2 * Copyright (C) 2011 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.tradefed.build; 17 18 import static org.junit.Assert.*; 19 20 import com.android.tradefed.util.FileUtil; 21 import com.android.tradefed.util.StreamUtil; 22 23 import org.easymock.EasyMock; 24 import org.easymock.IAnswer; 25 import org.easymock.IExpectationSetters; 26 import org.junit.After; 27 import org.junit.Before; 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.FileInputStream; 34 import java.io.IOException; 35 36 /** Unit tests for {@link FileDownloadCache}. */ 37 @RunWith(JUnit4.class) 38 public class FileDownloadCacheTest { 39 40 private static final String REMOTE_PATH = "foo/path"; 41 private static final String DOWNLOADED_CONTENTS = "downloaded contents"; 42 43 private IFileDownloader mMockDownloader; 44 45 private File mCacheDir; 46 private FileDownloadCache mCache; 47 private boolean mFailCopy = false; 48 49 @Before 50 public void setUp() throws Exception { 51 mMockDownloader = EasyMock.createMock(IFileDownloader.class); 52 mCacheDir = FileUtil.createTempDir("unittest"); 53 mCache = new FileDownloadCache(mCacheDir); 54 } 55 56 @After 57 public void tearDown() throws Exception { 58 mCache.empty(); 59 FileUtil.recursiveDelete(mCacheDir); 60 } 61 62 /** Test basic case for {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)}. */ 63 @Test 64 public void testFetchRemoteFile() throws Exception { 65 setDownloadExpections(); 66 EasyMock.replay(mMockDownloader); 67 assertFetchRemoteFile(); 68 EasyMock.verify(mMockDownloader); 69 } 70 71 /** 72 * Test {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)} when file can be 73 * retrieved from cache. 74 */ 75 @Test 76 public void testFetchRemoteFile_cacheHit() throws Exception { 77 setDownloadExpections(); 78 EasyMock.replay(mMockDownloader); 79 assertFetchRemoteFile(); 80 // now retrieve file again 81 assertFetchRemoteFile(); 82 // verify only one download call occurred 83 EasyMock.verify(mMockDownloader); 84 } 85 86 /** 87 * Test {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)} when cache grows 88 * larger than max 89 */ 90 @Test 91 public void testFetchRemoteFile_cacheSizeExceeded() throws Exception { 92 final String remotePath2 = "anotherpath"; 93 // set cache size to be small 94 mCache.setMaxCacheSize(DOWNLOADED_CONTENTS.length() + 1); 95 setDownloadExpections(remotePath2); 96 setDownloadExpections(); 97 EasyMock.replay(mMockDownloader); 98 assertFetchRemoteFile(remotePath2); 99 // now retrieve another file, which will exceed size of cache 100 assertFetchRemoteFile(); 101 assertNotNull(mCache.getCachedFile(REMOTE_PATH)); 102 assertNull(mCache.getCachedFile(remotePath2)); 103 EasyMock.verify(mMockDownloader); 104 } 105 106 /** 107 * Test {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)} when download fails 108 */ 109 @Test 110 public void testFetchRemoteFile_downloadFailed() throws Exception { 111 mMockDownloader.downloadFile(EasyMock.eq(REMOTE_PATH), 112 (File)EasyMock.anyObject()); 113 EasyMock.expectLastCall().andThrow(new BuildRetrievalError("download error")); 114 EasyMock.replay(mMockDownloader); 115 try { 116 mCache.fetchRemoteFile(mMockDownloader, REMOTE_PATH); 117 fail("BuildRetrievalError not thrown"); 118 } catch (BuildRetrievalError e) { 119 // expected 120 } 121 assertNull(mCache.getCachedFile(REMOTE_PATH)); 122 EasyMock.verify(mMockDownloader); 123 } 124 125 /** 126 * Test {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)} when download fails 127 * with RuntimeException. 128 */ 129 @Test 130 public void testFetchRemoteFile_downloadFailed_Runtime() throws Exception { 131 mMockDownloader.downloadFile(EasyMock.eq(REMOTE_PATH), (File) EasyMock.anyObject()); 132 EasyMock.expectLastCall().andThrow(new RuntimeException("download error")); 133 EasyMock.replay(mMockDownloader); 134 try { 135 mCache.fetchRemoteFile(mMockDownloader, REMOTE_PATH); 136 fail("RuntimeException not thrown"); 137 } catch (RuntimeException e) { 138 // expected 139 } 140 assertNull(mCache.getCachedFile(REMOTE_PATH)); 141 EasyMock.verify(mMockDownloader); 142 } 143 144 /** 145 * Test {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)} when copy of a cached 146 * file is missing 147 */ 148 @Test 149 public void testFetchRemoteFile_cacheMissing() throws Exception { 150 // perform successful download 151 setDownloadExpections(REMOTE_PATH).times(2); 152 EasyMock.replay(mMockDownloader); 153 assertFetchRemoteFile(REMOTE_PATH); 154 // now be sneaky and delete the cachedFile, so copy will fail 155 File cachedFile = mCache.getCachedFile(REMOTE_PATH); 156 assertNotNull(cachedFile); 157 cachedFile.delete(); 158 File file = null; 159 try { 160 file = mCache.fetchRemoteFile(mMockDownloader, REMOTE_PATH); 161 // file should have been updated in cache. 162 assertNotNull(file); 163 assertNotNull(mCache.getCachedFile(REMOTE_PATH)); 164 EasyMock.verify(mMockDownloader); 165 } finally { 166 FileUtil.deleteFile(file); 167 } 168 } 169 170 /** 171 * Test {@link FileDownloadCache#fetchRemoteFile(IFileDownloader, String)} when copy of a cached 172 * file fails 173 */ 174 @Test 175 public void testFetchRemoteFile_copyFailed() throws Exception { 176 mCache = 177 new FileDownloadCache(mCacheDir) { 178 @Override 179 File copyFile(String remotePath, File cachedFile) throws BuildRetrievalError { 180 if (mFailCopy) { 181 FileUtil.deleteFile(cachedFile); 182 } 183 return super.copyFile(remotePath, cachedFile); 184 } 185 }; 186 // perform successful download 187 setDownloadExpections(REMOTE_PATH); 188 EasyMock.replay(mMockDownloader); 189 assertFetchRemoteFile(REMOTE_PATH); 190 mFailCopy = true; 191 try { 192 mCache.fetchRemoteFile(mMockDownloader, REMOTE_PATH); 193 fail("BuildRetrievalError not thrown"); 194 } catch (BuildRetrievalError e) { 195 // expected 196 } 197 // file should be removed from cache 198 assertNull(mCache.getCachedFile(REMOTE_PATH)); 199 EasyMock.verify(mMockDownloader); 200 } 201 202 /** 203 * Perform one fetchRemoteFile call and verify contents for default remote path 204 */ 205 private void assertFetchRemoteFile() throws BuildRetrievalError, IOException { 206 assertFetchRemoteFile(REMOTE_PATH); 207 } 208 209 /** 210 * Perform one fetchRemoteFile call and verify contents 211 */ 212 private void assertFetchRemoteFile(String remotePath) throws BuildRetrievalError, IOException { 213 // test downloading file not in cache 214 File fileCopy = mCache.fetchRemoteFile(mMockDownloader, remotePath); 215 try { 216 assertNotNull(mCache.getCachedFile(remotePath)); 217 String contents = StreamUtil.getStringFromStream(new FileInputStream(fileCopy)); 218 assertEquals(DOWNLOADED_CONTENTS, contents); 219 } finally { 220 fileCopy.delete(); 221 } 222 } 223 224 /** 225 * Set EasyMock expectations for a downloadFile call for default remote path 226 */ 227 private void setDownloadExpections() throws BuildRetrievalError { 228 setDownloadExpections(REMOTE_PATH); 229 } 230 231 /** Set EasyMock expectations for a downloadFile call */ 232 private IExpectationSetters<Object> setDownloadExpections(String remotePath) 233 throws BuildRetrievalError { 234 IAnswer<Object> downloadAnswer = new IAnswer<Object>() { 235 @Override 236 public Object answer() throws Throwable { 237 File fileArg = (File) EasyMock.getCurrentArguments()[1]; 238 FileUtil.writeToFile("downloaded contents", fileArg); 239 return null; 240 } 241 }; 242 mMockDownloader.downloadFile(EasyMock.eq(remotePath), 243 EasyMock.<File>anyObject()); 244 return EasyMock.expectLastCall().andAnswer(downloadAnswer); 245 } 246 } 247