Test file errors in downloads.

Uses an error injection technique to simulate hard-to-reproduce file system errors.

BUG=None
TEST=None

Review URL: http://codereview.chromium.org/9426029

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126732 0039d316-1c4b-4281-b951-d872f2087c98
parent 688303b4
...@@ -142,6 +142,14 @@ class CONTENT_EXPORT DownloadFileManager ...@@ -142,6 +142,14 @@ class CONTENT_EXPORT DownloadFileManager
return downloads_.size(); return downloads_.size();
} }
void SetFileFactoryForTesting(scoped_ptr<DownloadFileFactory> file_factory) {
download_file_factory_.reset(file_factory.release());
}
DownloadFileFactory* GetFileFactoryForTesting() const {
return download_file_factory_.get(); // Explicitly NOT a scoped_ptr.
}
private: private:
friend class base::RefCountedThreadSafe<DownloadFileManager>; friend class base::RefCountedThreadSafe<DownloadFileManager>;
friend class DownloadFileManagerTest; friend class DownloadFileManagerTest;
......
...@@ -571,6 +571,8 @@ void DownloadItemImpl::TransitionTo(DownloadState new_state) { ...@@ -571,6 +571,8 @@ void DownloadItemImpl::TransitionTo(DownloadState new_state) {
break; break;
} }
VLOG(20) << " " << __FUNCTION__ << "()" << " this = " << DebugString(true);
UpdateObservers(); UpdateObservers();
bool is_done = (state_ != IN_PROGRESS); bool is_done = (state_ != IN_PROGRESS);
...@@ -989,19 +991,21 @@ std::string DownloadItemImpl::DebugString(bool verbose) const { ...@@ -989,19 +991,21 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
if (verbose) { if (verbose) {
description += base::StringPrintf( description += base::StringPrintf(
" db_handle = %" PRId64 " db_handle = %" PRId64
" total_bytes = %" PRId64 " total = %" PRId64
" received_bytes = %" PRId64 " received = %" PRId64
" is_paused = %c" " reason = %s"
" is_otr = %c" " paused = %c"
" safety_state = %s" " otr = %c"
" safety = %s"
" last_modified = '%s'" " last_modified = '%s'"
" etag = '%s'" " etag = '%s'"
" url_chain = \n\t\"%s\"\n\t" " url_chain = \n\t\"%s\"\n\t"
" target_name = \"%" PRFilePath "\"" " target = \"%" PRFilePath "\""
" full_path = \"%" PRFilePath "\"", " full_path = \"%" PRFilePath "\"",
GetDbHandle(), GetDbHandle(),
GetTotalBytes(), GetTotalBytes(),
GetReceivedBytes(), GetReceivedBytes(),
InterruptReasonDebugString(last_reason_).c_str(),
IsPaused() ? 'T' : 'F', IsPaused() ? 'T' : 'F',
IsOtr() ? 'T' : 'F', IsOtr() ? 'T' : 'F',
DebugSafetyStateString(GetSafetyState()), DebugSafetyStateString(GetSafetyState()),
......
...@@ -250,6 +250,10 @@ bool DownloadResourceHandler::OnResponseCompleted( ...@@ -250,6 +250,10 @@ bool DownloadResourceHandler::OnResponseCompleted(
int request_id, int request_id,
const net::URLRequestStatus& status, const net::URLRequestStatus& status,
const std::string& security_info) { const std::string& security_info) {
VLOG(20) << __FUNCTION__ << "()" << DebugString()
<< " request_id = " << request_id
<< " status.status() = " << status.status()
<< " status.error() = " << status.error();
if (download_id_.IsValid()) { if (download_id_.IsValid()) {
OnResponseCompletedInternal(request_id, status, security_info); OnResponseCompletedInternal(request_id, status, security_info);
} else { } else {
...@@ -268,7 +272,8 @@ void DownloadResourceHandler::OnResponseCompletedInternal( ...@@ -268,7 +272,8 @@ void DownloadResourceHandler::OnResponseCompletedInternal(
int request_id, int request_id,
const net::URLRequestStatus& status, const net::URLRequestStatus& status,
const std::string& security_info) { const std::string& security_info) {
VLOG(20) << __FUNCTION__ << "()" << DebugString() // NOTE: |request_| may be a dangling pointer at this point.
VLOG(20) << __FUNCTION__ << "()"
<< " request_id = " << request_id << " request_id = " << request_id
<< " status.status() = " << status.status() << " status.status() = " << status.status()
<< " status.error() = " << status.error(); << " status.error() = " << status.error();
......
...@@ -92,6 +92,8 @@ ...@@ -92,6 +92,8 @@
'test/test_browser_thread.h', 'test/test_browser_thread.h',
'test/test_content_client.cc', 'test/test_content_client.cc',
'test/test_content_client.h', 'test/test_content_client.h',
'test/test_file_error_injector.cc',
'test/test_file_error_injector.h',
'test/test_navigation_observer.cc', 'test/test_navigation_observer.cc',
'test/test_navigation_observer.h', 'test/test_navigation_observer.h',
'test/test_notification_tracker.cc', 'test/test_notification_tracker.cc',
......
// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
...@@ -20,11 +20,13 @@ namespace content { ...@@ -20,11 +20,13 @@ namespace content {
// sessions, but their local() field is. // sessions, but their local() field is.
class DownloadId { class DownloadId {
public: public:
static DownloadId Invalid() { return DownloadId(NULL, -1); } static DownloadId Invalid() { return DownloadId(); }
// Domain separates spaces of local ids. // Domain separates spaces of local ids.
typedef const void* Domain; typedef const void* Domain;
DownloadId() : domain_(NULL), local_id_(-1) {}
DownloadId(Domain domain, int32 local_id) DownloadId(Domain domain, int32 local_id)
: domain_(domain), : domain_(domain),
local_id_(local_id) { local_id_(local_id) {
......
This diff is collapsed.
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_TEST_TEST_FILE_ERROR_INJECTOR_H_
#define CONTENT_TEST_TEST_FILE_ERROR_INJECTOR_H_
#pragma once
#include <map>
#include <string>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "net/base/net_errors.h"
class GURL;
namespace content {
class DownloadId;
class DownloadFileWithErrorsFactory;
// Test helper for injecting errors into download file operations.
// All errors for a download must be injected before it starts.
// This class needs to be |RefCountedThreadSafe| because the implementation
// is referenced by other classes that live past the time when the user is
// nominally done with it. These classes are internal to content/.
//
// NOTE: No more than one download with the same URL can be in progress at
// the same time. You can have multiple simultaneous downloads as long as the
// URLs are different, as the URLs are used as keys to get information about
// the download.
//
// Example:
//
// FileErrorInfo a = { url1, ... };
// FileErrorInfo b = { url2, ... };
//
// scoped_refptr<TestFileErrorInjector> injector =
// TestFileErrorInjector::Create();
//
// injector->AddError(a);
// injector->AddError(b);
// injector->InjectErrors();
//
// download_manager->DownloadUrl(url1, ...);
// download_manager->DownloadUrl(url2, ...);
// ... wait for downloads to finish or get an injected error ...
class TestFileErrorInjector
: public base::RefCountedThreadSafe<TestFileErrorInjector> {
public:
enum FileOperationCode {
FILE_OPERATION_INITIALIZE,
FILE_OPERATION_WRITE,
FILE_OPERATION_RENAME
};
// Structure that encapsulates the information needed to inject a file error.
struct FileErrorInfo {
std::string url; // Full URL of the download. Identifies the download.
FileOperationCode code; // Operation to affect.
int operation_instance; // 0-based count of operation calls, for each code.
net::Error net_error; // Error to inject.
};
typedef std::map<std::string, FileErrorInfo> ErrorMap;
// Creates an instance. May only be called once.
// Lives until all callbacks (in the implementation) are complete and the
// creator goes out of scope.
static scoped_refptr<TestFileErrorInjector> Create();
// Adds an error.
// Must be called before |InjectErrors()| for a particular download file.
// It is an error to call |AddError()| more than once for the same file
// (URL), unless you call |ClearErrors()| in between them.
bool AddError(const FileErrorInfo& error_info);
// Clears all errors.
// Only affects files created after the next call to InjectErrors().
void ClearErrors();
// Injects the errors such that new download files will be affected.
// The download system must already be initialized before calling this.
// Multiple calls are allowed, but only useful if the errors have changed.
// Replaces the injected error list.
bool InjectErrors();
// Tells how many files are currently open.
size_t CurrentFileCount() const;
// Tells how many files have ever been open (since construction or the
// last call to |ClearFoundFiles()|).
size_t TotalFileCount() const;
// Returns whether or not a file matching |url| has been created.
bool HadFile(const GURL& url) const;
// Gets the download ID associated with the file matching |url|.
const content::DownloadId GetId(const GURL& url) const;
// Resets the found file list.
void ClearFoundFiles();
static std::string DebugString(FileOperationCode code);
private:
friend class base::RefCountedThreadSafe<TestFileErrorInjector>;
typedef std::map<GURL, content::DownloadId> FileMap;
TestFileErrorInjector();
virtual ~TestFileErrorInjector();
void AddFactory(scoped_ptr<DownloadFileWithErrorsFactory> factory);
void InjectErrorsOnFileThread(ErrorMap map,
DownloadFileWithErrorsFactory* factory);
// Callbacks from the download file, to record lifetimes.
// These may be called on any thread.
void RecordDownloadFileConstruction(const GURL& url, content::DownloadId id);
void RecordDownloadFileDestruction(const GURL& url);
// These run on the UI thread.
void DownloadFileCreated(GURL url, content::DownloadId id);
void DestroyingDownloadFile(GURL url);
// All the data is used on the UI thread.
// Our injected error list, mapped by URL. One per file.
ErrorMap injected_errors_;
// Keep track of active DownloadFiles.
FileMap files_;
// Keep track of found DownloadFiles.
FileMap found_files_;
// The factory we created. May outlive this class.
DownloadFileWithErrorsFactory* created_factory_;
DISALLOW_COPY_AND_ASSIGN(TestFileErrorInjector);
};
} // namespace content
#endif // CONTENT_TEST_TEST_FILE_ERROR_INJECTOR_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment