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