| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.offlinepages; | 5 package org.chromium.chrome.browser.offlinepages; |
| 6 | 6 |
| 7 import android.app.NotificationManager; | 7 import android.app.NotificationManager; |
| 8 import android.content.Context; | 8 import android.content.Context; |
| 9 import android.os.Environment; | 9 import android.os.Environment; |
| 10 import android.text.TextUtils; | 10 import android.text.TextUtils; |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 private OfflinePageEvaluationBridge mBridge; | 89 private OfflinePageEvaluationBridge mBridge; |
| 90 private OfflinePageEvaluationObserver mObserver; | 90 private OfflinePageEvaluationObserver mObserver; |
| 91 | 91 |
| 92 private CountDownLatch mCompletionLatch; | 92 private CountDownLatch mCompletionLatch; |
| 93 private List<String> mUrls; | 93 private List<String> mUrls; |
| 94 private int mCount; | 94 private int mCount; |
| 95 private boolean mIsUserRequested; | 95 private boolean mIsUserRequested; |
| 96 private boolean mUseTestScheduler; | 96 private boolean mUseTestScheduler; |
| 97 | 97 |
| 98 private LongSparseArray<RequestMetadata> mRequestMetadata; | 98 private LongSparseArray<RequestMetadata> mRequestMetadata; |
| 99 private OutputStreamWriter mLogOutput; | |
| 100 | 99 |
| 101 public OfflinePageSavePageLaterEvaluationTest() { | 100 public OfflinePageSavePageLaterEvaluationTest() { |
| 102 super(ChromeActivity.class); | 101 super(ChromeActivity.class); |
| 103 } | 102 } |
| 104 | 103 |
| 105 @Override | 104 @Override |
| 106 protected void setUp() throws Exception { | 105 protected void setUp() throws Exception { |
| 107 super.setUp(); | 106 super.setUp(); |
| 108 mRequestMetadata = new LongSparseArray<RequestMetadata>(); | 107 mRequestMetadata = new LongSparseArray<RequestMetadata>(); |
| 109 mCount = 0; | 108 mCount = 0; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 131 public void onResult(Integer removedCount) { | 130 public void onResult(Integer removedCount) { |
| 132 mClearingSemaphore.release(); | 131 mClearingSemaphore.release(); |
| 133 } | 132 } |
| 134 }); | 133 }); |
| 135 } | 134 } |
| 136 }); | 135 }); |
| 137 } | 136 } |
| 138 }); | 137 }); |
| 139 checkTrue(mClearingSemaphore.tryAcquire(REMOVE_REQUESTS_TIMEOUT_MS, Time
Unit.MILLISECONDS), | 138 checkTrue(mClearingSemaphore.tryAcquire(REMOVE_REQUESTS_TIMEOUT_MS, Time
Unit.MILLISECONDS), |
| 140 "Timed out when clearing remaining requests!"); | 139 "Timed out when clearing remaining requests!"); |
| 140 mBridge.closeLog(); |
| 141 super.tearDown(); | 141 super.tearDown(); |
| 142 } | 142 } |
| 143 | 143 |
| 144 @Override | 144 @Override |
| 145 public void startMainActivity() throws InterruptedException { | 145 public void startMainActivity() throws InterruptedException { |
| 146 startMainActivityOnBlankPage(); | 146 startMainActivityOnBlankPage(); |
| 147 } | 147 } |
| 148 | 148 |
| 149 /** | 149 /** |
| 150 * Get a reader for a given input file path. | 150 * Get a reader for a given input file path. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 171 File externalArchiveDir = | 171 File externalArchiveDir = |
| 172 new File(Environment.getExternalStorageDirectory(), SAVED_PAGES_
EXTERNAL_PATH); | 172 new File(Environment.getExternalStorageDirectory(), SAVED_PAGES_
EXTERNAL_PATH); |
| 173 try { | 173 try { |
| 174 // Clear the old archive folder. | 174 // Clear the old archive folder. |
| 175 if (externalArchiveDir.exists()) { | 175 if (externalArchiveDir.exists()) { |
| 176 String[] files = externalArchiveDir.list(); | 176 String[] files = externalArchiveDir.list(); |
| 177 if (files != null) { | 177 if (files != null) { |
| 178 for (String file : files) { | 178 for (String file : files) { |
| 179 File currentFile = new File(externalArchiveDir.getPath()
, file); | 179 File currentFile = new File(externalArchiveDir.getPath()
, file); |
| 180 if (!currentFile.delete()) { | 180 if (!currentFile.delete()) { |
| 181 logError(file + " cannot be deleted when clearing pr
evious archives."); | 181 log(file + " cannot be deleted when clearing previou
s archives."); |
| 182 } | 182 } |
| 183 } | 183 } |
| 184 } | 184 } |
| 185 } else if (!externalArchiveDir.mkdir()) { | 185 } |
| 186 logError("Cannot create directory on external storage to store s
aved pages."); | 186 if (!externalArchiveDir.mkdir()) { |
| 187 log("Cannot create directory on external storage to store saved
pages."); |
| 187 } | 188 } |
| 188 } catch (SecurityException e) { | 189 } catch (SecurityException e) { |
| 189 logError("Failed to delete or create external archive folder!"); | 190 log("Failed to delete or create external archive folder!"); |
| 190 } | 191 } |
| 191 return externalArchiveDir; | 192 return externalArchiveDir; |
| 192 } | 193 } |
| 193 | 194 |
| 194 /** | 195 /** |
| 195 * Logs error in both console and output file. | 196 * Print log message in output file through evaluation bridge. |
| 196 */ | 197 */ |
| 197 private void logError(String error) { | 198 private void log(String message) { |
| 198 Log.e(TAG, error); | 199 mBridge.log(TAG, message); |
| 199 if (mLogOutput != null) { | |
| 200 try { | |
| 201 mLogOutput.write(error + NEW_LINE); | |
| 202 mLogOutput.flush(); | |
| 203 } catch (Exception e) { | |
| 204 Log.e(TAG, e.getMessage(), e); | |
| 205 } | |
| 206 } | |
| 207 } | 200 } |
| 208 | 201 |
| 209 /** | 202 /** |
| 210 * Assert the condition is true, otherwise abort the test and log. | 203 * Assert the condition is true, otherwise abort the test and log. |
| 211 */ | 204 */ |
| 212 private void checkTrue(boolean condition, String message) { | 205 private void checkTrue(boolean condition, String message) { |
| 213 if (!condition) { | 206 if (!condition) { |
| 214 logError(message); | 207 log(message); |
| 215 if (mLogOutput != null) { | |
| 216 try { | |
| 217 mLogOutput.close(); | |
| 218 } catch (IOException e) { | |
| 219 Log.e(TAG, e.getMessage(), e); | |
| 220 } | |
| 221 } | |
| 222 fail(); | 208 fail(); |
| 223 } | 209 } |
| 224 } | 210 } |
| 225 | 211 |
| 226 /** | 212 /** |
| 227 * Initializes the evaluation bridge which will be used. | 213 * Initializes the evaluation bridge which will be used. |
| 228 * @param useCustomScheduler True if customized scheduler (the one with imme
diate scheduling) | 214 * @param useCustomScheduler True if customized scheduler (the one with imme
diate scheduling) |
| 229 * will be used. False otherwise. | 215 * will be used. False otherwise. |
| 230 */ | 216 */ |
| 231 private void initializeBridgeForProfile(final boolean useTestingScheduler) | 217 private void initializeBridgeForProfile(final boolean useTestingScheduler) |
| 232 throws InterruptedException { | 218 throws InterruptedException { |
| 233 final Semaphore semaphore = new Semaphore(0); | 219 final Semaphore semaphore = new Semaphore(0); |
| 234 ThreadUtils.runOnUiThread(new Runnable() { | 220 ThreadUtils.runOnUiThread(new Runnable() { |
| 235 @Override | 221 @Override |
| 236 public void run() { | 222 public void run() { |
| 237 Profile profile = Profile.getLastUsedProfile(); | 223 Profile profile = Profile.getLastUsedProfile(); |
| 238 mBridge = OfflinePageEvaluationBridge.getForProfile(profile, use
TestingScheduler); | 224 mBridge = OfflinePageEvaluationBridge.getForProfile(profile, use
TestingScheduler); |
| 239 if (mBridge == null) { | 225 if (mBridge == null) { |
| 240 logError("OfflinePageEvaluationBridge initialization failed!
"); | 226 fail("OfflinePageEvaluationBridge initialization failed!"); |
| 241 return; | 227 return; |
| 242 } | 228 } |
| 243 if (mBridge.isOfflinePageModelLoaded()) { | 229 if (mBridge.isOfflinePageModelLoaded()) { |
| 244 semaphore.release(); | 230 semaphore.release(); |
| 245 return; | 231 return; |
| 246 } | 232 } |
| 247 mBridge.addObserver(new OfflinePageEvaluationObserver() { | 233 mBridge.addObserver(new OfflinePageEvaluationObserver() { |
| 248 @Override | 234 @Override |
| 249 public void offlinePageModelLoaded() { | 235 public void offlinePageModelLoaded() { |
| 250 semaphore.release(); | 236 semaphore.release(); |
| 251 mBridge.removeObserver(this); | 237 mBridge.removeObserver(this); |
| 252 } | 238 } |
| 253 }); | 239 }); |
| 254 } | 240 } |
| 255 }); | 241 }); |
| 256 checkTrue(semaphore.tryAcquire(PAGE_MODEL_LOAD_TIMEOUT_MS, TimeUnit.MILL
ISECONDS), | 242 checkTrue(semaphore.tryAcquire(PAGE_MODEL_LOAD_TIMEOUT_MS, TimeUnit.MILL
ISECONDS), |
| 257 "Timed out when loading OfflinePageModel!"); | 243 "Timed out when loading OfflinePageModel!"); |
| 258 } | 244 } |
| 259 | 245 |
| 260 /** | 246 /** |
| 261 * Set up the input/output, bridge and observer we're going to use. | 247 * Set up the input/output, bridge and observer we're going to use. |
| 262 * @param useCustomScheduler True if customized scheduler (the one with imme
diate scheduling) | 248 * @param useCustomScheduler True if customized scheduler (the one with imme
diate scheduling) |
| 263 * will be used. False otherwise. | 249 * will be used. False otherwise. |
| 264 */ | 250 */ |
| 265 protected void setUpIOAndBridge(final boolean useCustomScheduler) throws Int
erruptedException { | 251 protected void setUpIOAndBridge(final boolean useCustomScheduler) throws Int
erruptedException { |
| 266 try { | 252 try { |
| 267 mLogOutput = getOutputStream(LOG_OUTPUT_FILE_PATH); | |
| 268 } catch (IOException e) { | |
| 269 Log.wtf(TAG, "Cannot set output file!"); | |
| 270 Log.wtf(TAG, e.getMessage(), e); | |
| 271 } | |
| 272 try { | |
| 273 getUrlListFromInputFile(INPUT_FILE_PATH); | 253 getUrlListFromInputFile(INPUT_FILE_PATH); |
| 274 } catch (IOException e) { | 254 } catch (IOException e) { |
| 275 Log.wtf(TAG, "Cannot read input file!"); | 255 Log.wtf(TAG, "Cannot read input file!", e); |
| 276 Log.wtf(TAG, e.getMessage(), e); | |
| 277 } | 256 } |
| 278 checkTrue(mUrls != null, "URLs weren't loaded."); | 257 checkTrue(mUrls != null, "URLs weren't loaded."); |
| 279 checkTrue(mUrls.size() > 0, "No valid URLs in the input file."); | 258 checkTrue(mUrls.size() > 0, "No valid URLs in the input file."); |
| 280 | 259 |
| 281 mCompletionLatch = new CountDownLatch(1); | 260 mCompletionLatch = new CountDownLatch(1); |
| 282 | 261 |
| 283 initializeBridgeForProfile(useCustomScheduler); | 262 initializeBridgeForProfile(useCustomScheduler); |
| 284 mObserver = new OfflinePageEvaluationObserver() { | 263 mObserver = new OfflinePageEvaluationObserver() { |
| 285 public void savePageRequestAdded(SavePageRequest request) { | 264 public void savePageRequestAdded(SavePageRequest request) { |
| 286 RequestMetadata metadata = new RequestMetadata(); | 265 RequestMetadata metadata = new RequestMetadata(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 300 } | 279 } |
| 301 metadata.mStatus = status; | 280 metadata.mStatus = status; |
| 302 if (mCount == mUrls.size()) { | 281 if (mCount == mUrls.size()) { |
| 303 mCompletionLatch.countDown(); | 282 mCompletionLatch.countDown(); |
| 304 return; | 283 return; |
| 305 } | 284 } |
| 306 } | 285 } |
| 307 public void savePageRequestChanged(SavePageRequest request) {} | 286 public void savePageRequestChanged(SavePageRequest request) {} |
| 308 }; | 287 }; |
| 309 mBridge.addObserver(mObserver); | 288 mBridge.addObserver(mObserver); |
| 289 try { |
| 290 File logOutputFile = |
| 291 new File(Environment.getExternalStorageDirectory(), LOG_OUTP
UT_FILE_PATH); |
| 292 mBridge.setLogOutputFile(logOutputFile); |
| 293 } catch (IOException e) { |
| 294 Log.wtf(TAG, "Cannot set log output file!", e); |
| 295 } |
| 310 } | 296 } |
| 311 | 297 |
| 312 /** | 298 /** |
| 313 * Calls SavePageLater on the bridge to try to offline an url. | 299 * Calls SavePageLater on the bridge to try to offline an url. |
| 314 * @param url The url to be saved. | 300 * @param url The url to be saved. |
| 315 * @param namespace The namespace this request belongs to. | 301 * @param namespace The namespace this request belongs to. |
| 316 */ | 302 */ |
| 317 private void savePageLater(final String url, final String namespace) | 303 private void savePageLater(final String url, final String namespace) |
| 318 throws InterruptedException { | 304 throws InterruptedException { |
| 319 ThreadUtils.runOnUiThread(new Runnable() { | 305 ThreadUtils.runOnUiThread(new Runnable() { |
| 320 @Override | 306 @Override |
| 321 public void run() { | 307 public void run() { |
| 322 mBridge.savePageLater(url, namespace, mIsUserRequested); | 308 mBridge.savePageLater(url, namespace, mIsUserRequested); |
| 323 } | 309 } |
| 324 }); | 310 }); |
| 325 } | 311 } |
| 326 | 312 |
| 327 private void processUrls(List<String> urls) throws InterruptedException, IOE
xception { | 313 private void processUrls(List<String> urls) throws InterruptedException, IOE
xception { |
| 328 if (mBridge == null) { | 314 if (mBridge == null) { |
| 329 logError("Test initialization error, aborting. No results would be w
ritten."); | 315 fail("Test initialization error, aborting. No results would be writt
en."); |
| 330 return; | 316 return; |
| 331 } | 317 } |
| 332 for (String url : mUrls) { | 318 for (String url : mUrls) { |
| 333 savePageLater(url, NAMESPACE); | 319 savePageLater(url, NAMESPACE); |
| 334 } | 320 } |
| 335 | 321 |
| 336 mCompletionLatch.await(); | 322 mCompletionLatch.await(); |
| 337 writeResults(); | 323 writeResults(); |
| 338 } | 324 } |
| 339 | 325 |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 * https://www.google.com/;SUCCESS;110 KB;273805 | 407 * https://www.google.com/;SUCCESS;110 KB;273805 |
| 422 * At the end of the file there will be a summary: | 408 * At the end of the file there will be a summary: |
| 423 * Total requested URLs: XX, Completed: XX, Failed: XX, Failure Rate: XX.XX% | 409 * Total requested URLs: XX, Completed: XX, Failed: XX, Failure Rate: XX.XX% |
| 424 */ | 410 */ |
| 425 private void writeResults() throws IOException, InterruptedException { | 411 private void writeResults() throws IOException, InterruptedException { |
| 426 loadSavedPages(); | 412 loadSavedPages(); |
| 427 OutputStreamWriter output = getOutputStream(RESULT_OUTPUT_FILE_PATH); | 413 OutputStreamWriter output = getOutputStream(RESULT_OUTPUT_FILE_PATH); |
| 428 try { | 414 try { |
| 429 int failedCount = 0; | 415 int failedCount = 0; |
| 430 if (mCount < mUrls.size()) { | 416 if (mCount < mUrls.size()) { |
| 431 logError("Test terminated before all requests completed."); | 417 log("Test terminated before all requests completed."); |
| 432 } | 418 } |
| 433 File externalArchiveDir = getExternalArchiveDir(); | 419 File externalArchiveDir = getExternalArchiveDir(); |
| 434 for (int i = 0; i < mRequestMetadata.size(); i++) { | 420 for (int i = 0; i < mRequestMetadata.size(); i++) { |
| 435 RequestMetadata metadata = mRequestMetadata.valueAt(i); | 421 RequestMetadata metadata = mRequestMetadata.valueAt(i); |
| 436 long requestId = metadata.mId; | 422 long requestId = metadata.mId; |
| 437 int status = metadata.mStatus; | 423 int status = metadata.mStatus; |
| 438 String url = metadata.mUrl; | 424 String url = metadata.mUrl; |
| 439 OfflinePageItem page = metadata.mPage; | 425 OfflinePageItem page = metadata.mPage; |
| 440 if (page == null) { | 426 if (page == null) { |
| 441 output.write(url + DELIMITER + statusToString(status) + NEW_
LINE); | 427 output.write(url + DELIMITER + statusToString(status) + NEW_
LINE); |
| 442 if (status != -1) { | 428 if (status != -1) { |
| 443 failedCount++; | 429 failedCount++; |
| 444 } | 430 } |
| 445 continue; | 431 continue; |
| 446 } | 432 } |
| 447 output.write(metadata.mUrl + DELIMITER + statusToString(status)
+ DELIMITER | 433 output.write(metadata.mUrl + DELIMITER + statusToString(status)
+ DELIMITER |
| 448 + page.getFileSize() / 1000 + " KB" + DELIMITER | 434 + page.getFileSize() / 1000 + " KB" + DELIMITER |
| 449 + metadata.mTimeDelta.getTimeDelta() + NEW_LINE); | 435 + metadata.mTimeDelta.getTimeDelta() + NEW_LINE); |
| 450 // Move the page to external storage if external archive exists. | 436 // Move the page to external storage if external archive exists. |
| 451 File originalPage = new File(page.getFilePath()); | 437 File originalPage = new File(page.getFilePath()); |
| 452 File externalPage = new File(externalArchiveDir, originalPage.ge
tName()); | 438 File externalPage = new File(externalArchiveDir, originalPage.ge
tName()); |
| 453 if (!OfflinePageUtils.copyToShareableLocation(originalPage, exte
rnalPage)) { | 439 if (!OfflinePageUtils.copyToShareableLocation(originalPage, exte
rnalPage)) { |
| 454 logError("Saved page for url " + page.getUrl() + " cannot be
moved."); | 440 log("Saved page for url " + page.getUrl() + " cannot be move
d."); |
| 455 } | 441 } |
| 456 } | 442 } |
| 457 output.write(String.format( | 443 output.write(String.format( |
| 458 "Total requested URLs: %d, Completed: %d, Failed: %d, Failur
e Rate: %.2f%%" | 444 "Total requested URLs: %d, Completed: %d, Failed: %d, Failur
e Rate: %.2f%%" |
| 459 + NEW_LINE, | 445 + NEW_LINE, |
| 460 mUrls.size(), mCount, failedCount, (failedCount * 100.0 / mC
ount))); | 446 mUrls.size(), mCount, failedCount, (failedCount * 100.0 / mC
ount))); |
| 461 } catch (FileNotFoundException e) { | 447 } catch (FileNotFoundException e) { |
| 462 Log.e(TAG, e.getMessage(), e); | 448 Log.e(TAG, e.getMessage(), e); |
| 463 } finally { | 449 } finally { |
| 464 if (output != null) { | 450 if (output != null) { |
| 465 output.close(); | 451 output.close(); |
| 466 } | 452 } |
| 467 if (mLogOutput != null) { | |
| 468 mLogOutput.close(); | |
| 469 } | |
| 470 } | 453 } |
| 471 } | 454 } |
| 472 | 455 |
| 473 /** | 456 /** |
| 474 * Method to parse config files for test parameters. | 457 * Method to parse config files for test parameters. |
| 475 */ | 458 */ |
| 476 public void parseConfigFile() throws IOException { | 459 public void parseConfigFile() throws IOException { |
| 477 Properties properties = new Properties(); | 460 Properties properties = new Properties(); |
| 478 InputStream inputStream = null; | 461 InputStream inputStream = null; |
| 479 try { | 462 try { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 497 * The test is the entry point for all kinds of testing of SavePageLater. | 480 * The test is the entry point for all kinds of testing of SavePageLater. |
| 498 * It is encouraged to use run_offline_page_evaluation_test.py to run this t
est. | 481 * It is encouraged to use run_offline_page_evaluation_test.py to run this t
est. |
| 499 */ | 482 */ |
| 500 @Manual | 483 @Manual |
| 501 public void testFailureRate() throws IOException, InterruptedException { | 484 public void testFailureRate() throws IOException, InterruptedException { |
| 502 parseConfigFile(); | 485 parseConfigFile(); |
| 503 setUpIOAndBridge(mUseTestScheduler); | 486 setUpIOAndBridge(mUseTestScheduler); |
| 504 processUrls(mUrls); | 487 processUrls(mUrls); |
| 505 } | 488 } |
| 506 } | 489 } |
| OLD | NEW |