Add CefScopedTempDir and file utility functions for unit tests (issue #1632)

This commit is contained in:
Marshall Greenblatt 2016-11-15 12:56:02 -05:00
parent a7195c0103
commit 04642e0480
22 changed files with 1539 additions and 194 deletions

View File

@ -429,6 +429,7 @@ static_library("libcef_static") {
"libcef/common/extensions/extensions_client.h",
"libcef/common/extensions/extensions_util.cc",
"libcef/common/extensions/extensions_util.h",
"libcef/common/file_util_impl.cc",
"libcef/common/json_impl.cc",
"libcef/common/main_delegate.cc",
"libcef/common/main_delegate.h",
@ -1373,6 +1374,9 @@ cef_unittests_sources = [
"tests/unittests/dom_unittest.cc",
"tests/unittests/download_unittest.cc",
"tests/unittests/draggable_regions_unittest.cc",
"tests/unittests/file_util.cc",
"tests/unittests/file_util.h",
"tests/unittests/file_util_unittest.cc",
"tests/unittests/frame_unittest.cc",
"tests/unittests/geolocation_unittest.cc",
"tests/unittests/image_unittest.cc",
@ -1396,6 +1400,7 @@ cef_unittests_sources = [
"tests/unittests/routing_test_handler.h",
"tests/unittests/run_all_unittests.cc",
"tests/unittests/scheme_handler_unittest.cc",
"tests/unittests/scoped_temp_dir_unittest.cc",
"tests/unittests/stream_unittest.cc",
"tests/unittests/stream_resource_handler_unittest.cc",
"tests/unittests/string_unittest.cc",
@ -1695,6 +1700,8 @@ if (is_mac) {
"tests/unittests/client_app_delegates.cc",
"tests/unittests/cookie_unittest.cc",
"tests/unittests/dom_unittest.cc",
"tests/unittests/file_util.cc",
"tests/unittests/file_util.h",
"tests/unittests/frame_unittest.cc",
"tests/unittests/message_router_unittest.cc",
"tests/unittests/navigation_unittest.cc",

View File

@ -28,6 +28,7 @@
'include/cef_download_item.h',
'include/cef_drag_data.h',
'include/cef_drag_handler.h',
'include/cef_file_util.h',
'include/cef_find_handler.h',
'include/cef_focus_handler.h',
'include/cef_frame.h',
@ -113,6 +114,7 @@
'include/capi/cef_download_item_capi.h',
'include/capi/cef_drag_data_capi.h',
'include/capi/cef_drag_handler_capi.h',
'include/capi/cef_file_util_capi.h',
'include/capi/cef_find_handler_capi.h',
'include/capi/cef_focus_handler_capi.h',
'include/capi/cef_frame_capi.h',

View File

@ -61,6 +61,7 @@
'include/wrapper/cef_helpers.h',
'include/wrapper/cef_message_router.h',
'include/wrapper/cef_resource_manager.h',
'include/wrapper/cef_scoped_temp_dir.h',
'include/wrapper/cef_stream_resource_handler.h',
'include/wrapper/cef_xml_object.h',
'include/wrapper/cef_zip_archive.h',
@ -125,6 +126,7 @@
'libcef_dll/wrapper/cef_closure_task.cc',
'libcef_dll/wrapper/cef_message_router.cc',
'libcef_dll/wrapper/cef_resource_manager.cc',
'libcef_dll/wrapper/cef_scoped_temp_dir.cc',
'libcef_dll/wrapper/cef_stream_resource_handler.cc',
'libcef_dll/wrapper/cef_xml_object.cc',
'libcef_dll/wrapper/cef_zip_archive.cc',

View File

@ -0,0 +1,118 @@
// Copyright (c) 2016 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef CEF_INCLUDE_CAPI_CEF_FILE_UTIL_CAPI_H_
#define CEF_INCLUDE_CAPI_CEF_FILE_UTIL_CAPI_H_
#pragma once
#include "include/capi/cef_base_capi.h"
#ifdef __cplusplus
extern "C" {
#endif
///
// Creates a directory and all parent directories if they don't already exist.
// Returns true (1) on successful creation or if the directory already exists.
// The directory is only readable by the current user. Calling this function on
// the browser process UI or IO threads is not allowed.
///
CEF_EXPORT int cef_create_directory(const cef_string_t* full_path);
///
// Get the temporary directory provided by the system.
//
// WARNING: In general, you should use the temp directory variants below instead
// of this function. Those variants will ensure that the proper permissions are
// set so that other users on the system can't edit them while they're open
// (which could lead to security issues).
///
CEF_EXPORT int cef_get_temp_directory(cef_string_t* temp_dir);
///
// Creates a new directory. On Windows if |prefix| is provided the new directory
// name is in the format of "prefixyyyy". Returns true (1) on success and sets
// |new_temp_path| to the full path of the directory that was created. The
// directory is only readable by the current user. Calling this function on the
// browser process UI or IO threads is not allowed.
///
CEF_EXPORT int cef_create_new_temp_directory(const cef_string_t* prefix,
cef_string_t* new_temp_path);
///
// Creates a directory within another directory. Extra characters will be
// appended to |prefix| to ensure that the new directory does not have the same
// name as an existing directory. Returns true (1) on success and sets |new_dir|
// to the full path of the directory that was created. The directory is only
// readable by the current user. Calling this function on the browser process UI
// or IO threads is not allowed.
///
CEF_EXPORT int cef_create_temp_directory_in_directory(
const cef_string_t* base_dir, const cef_string_t* prefix,
cef_string_t* new_dir);
///
// Returns true (1) if the given path exists and is a directory. Calling this
// function on the browser process UI or IO threads is not allowed.
///
CEF_EXPORT int cef_directory_exists(const cef_string_t* path);
///
// Deletes the given path whether it's a file or a directory. If |path| is a
// directory all contents will be deleted. If |recursive| is true (1) any sub-
// directories and their contents will also be deleted (equivalent to executing
// "rm -rf", so use with caution). On POSIX environments if |path| is a symbolic
// link then only the symlink will be deleted. Returns true (1) on successful
// deletion or if |path| does not exist. Calling this function on the browser
// process UI or IO threads is not allowed.
///
CEF_EXPORT int cef_delete_file(const cef_string_t* path, int recursive);
///
// Writes the contents of |src_dir| into a zip archive at |dest_file|. If
// |include_hidden_files| is true (1) files starting with "." will be included.
// Returns true (1) on success. Calling this function on the browser process UI
// or IO threads is not allowed.
///
CEF_EXPORT int cef_zip_directory(const cef_string_t* src_dir,
const cef_string_t* dest_file, int include_hidden_files);
#ifdef __cplusplus
}
#endif
#endif // CEF_INCLUDE_CAPI_CEF_FILE_UTIL_CAPI_H_

118
include/cef_file_util.h Normal file
View File

@ -0,0 +1,118 @@
// Copyright (c) 2016 Marshall A. Greenblatt. Portions copyright (c) 2012
// Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---------------------------------------------------------------------------
//
// The contents of this file must follow a specific format in order to
// support the CEF translator tool. See the translator.README.txt file in the
// tools directory for more information.
//
#ifndef CEF_INCLUDE_CEF_FILE_UTIL_H_
#define CEF_INCLUDE_CEF_FILE_UTIL_H_
#pragma once
#include "include/cef_base.h"
///
// Creates a directory and all parent directories if they don't already exist.
// Returns true on successful creation or if the directory already exists. The
// directory is only readable by the current user. Calling this function on the
// browser process UI or IO threads is not allowed.
///
/*--cef()--*/
bool CefCreateDirectory(const CefString& full_path);
///
// Get the temporary directory provided by the system.
//
// WARNING: In general, you should use the temp directory variants below instead
// of this function. Those variants will ensure that the proper permissions are
// set so that other users on the system can't edit them while they're open
// (which could lead to security issues).
///
/*--cef()--*/
bool CefGetTempDirectory(CefString& temp_dir);
///
// Creates a new directory. On Windows if |prefix| is provided the new directory
// name is in the format of "prefixyyyy". Returns true on success and sets
// |new_temp_path| to the full path of the directory that was created. The
// directory is only readable by the current user. Calling this function on the
// browser process UI or IO threads is not allowed.
///
/*--cef(optional_param=prefix)--*/
bool CefCreateNewTempDirectory(const CefString& prefix,
CefString& new_temp_path);
///
// Creates a directory within another directory. Extra characters will be
// appended to |prefix| to ensure that the new directory does not have the same
// name as an existing directory. Returns true on success and sets |new_dir| to
// the full path of the directory that was created. The directory is only
// readable by the current user. Calling this function on the browser process
// UI or IO threads is not allowed.
///
/*--cef(optional_param=prefix)--*/
bool CefCreateTempDirectoryInDirectory(const CefString& base_dir,
const CefString& prefix,
CefString& new_dir);
///
// Returns true if the given path exists and is a directory. Calling this
// function on the browser process UI or IO threads is not allowed.
///
/*--cef()--*/
bool CefDirectoryExists(const CefString& path);
///
// Deletes the given path whether it's a file or a directory. If |path| is a
// directory all contents will be deleted. If |recursive| is true any sub-
// directories and their contents will also be deleted (equivalent to executing
// "rm -rf", so use with caution). On POSIX environments if |path| is a symbolic
// link then only the symlink will be deleted. Returns true on successful
// deletion or if |path| does not exist. Calling this function on the browser
// process UI or IO threads is not allowed.
///
/*--cef()--*/
bool CefDeleteFile(const CefString& path, bool recursive);
///
// Writes the contents of |src_dir| into a zip archive at |dest_file|. If
// |include_hidden_files| is true files starting with "." will be included.
// Returns true on success. Calling this function on the browser process UI or
// IO threads is not allowed.
///
/*--cef()--*/
bool CefZipDirectory(const CefString& src_dir,
const CefString& dest_file,
bool include_hidden_files);
#endif // CEF_INCLUDE_CEF_FILE_UTIL_H_

View File

@ -0,0 +1,118 @@
// Copyright (c) 2016 Marshall A. Greenblatt. Portions copyright (c) 2011
// Google Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---------------------------------------------------------------------------
//
// The contents of this file are only available to applications that link
// against the libcef_dll_wrapper target.
//
#ifndef CEF_INCLUDE_SCOPED_TEMP_DIR_H_
#define CEF_INCLUDE_SCOPED_TEMP_DIR_H_
#pragma once
#include "include/base/cef_build.h"
#include "include/base/cef_macros.h"
#include "include/cef_base.h"
///
// An object representing a temporary / scratch directory that should be cleaned
// up (recursively) when this object goes out of scope. Note that since
// deletion occurs during the destructor, no further error handling is possible
// if the directory fails to be deleted. As a result, deletion is not
// guaranteed by this class.
//
// Multiple calls to the methods which establish a temporary directory
// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have
// intervening calls to Delete or Take, or the calls will fail.
///
class CefScopedTempDir {
public:
///
// No directory is owned/created initially.
///
CefScopedTempDir();
///
// Recursively delete path.
///
~CefScopedTempDir();
///
// Creates a unique directory in TempPath, and takes ownership of it.
// See file_util::CreateNewTemporaryDirectory.
///
bool CreateUniqueTempDir() WARN_UNUSED_RESULT;
///
// Creates a unique directory under a given path, and takes ownership of it.
///
bool CreateUniqueTempDirUnderPath(const CefString& path) WARN_UNUSED_RESULT;
///
// Takes ownership of directory at |path|, creating it if necessary.
// Don't call multiple times unless Take() has been called first.
///
bool Set(const CefString& path) WARN_UNUSED_RESULT;
///
// Deletes the temporary directory wrapped by this object.
///
bool Delete() WARN_UNUSED_RESULT;
///
// Caller takes ownership of the temporary directory so it won't be destroyed
// when this object goes out of scope.
///
CefString Take();
///
// Returns the path to the created directory. Call one of the
// CreateUniqueTempDir* methods before getting the path.
///
const CefString& GetPath() const;
///
// Returns true if path_ is empty.
///
bool IsEmpty() const;
///
// Returns true if path_ is non-empty and exists.
///
bool IsValid() const;
private:
CefString path_;
DISALLOW_COPY_AND_ASSIGN(CefScopedTempDir);
};
#endif // CEF_INCLUDE_SCOPED_TEMP_DIR_H_

View File

@ -0,0 +1,86 @@
// Copyright 2016 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "include/cef_file_util.h"
#include "include/cef_task.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "third_party/zlib/google/zip.h"
namespace {
bool AllowFileIO() {
if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
NOTREACHED() << "file IO is not allowed on the current thread";
return false;
}
return true;
}
} // namespace
bool CefCreateDirectory(const CefString& full_path) {
if (!AllowFileIO())
return false;
return base::CreateDirectory(full_path);
}
bool CefGetTempDirectory(CefString& temp_dir) {
if (!AllowFileIO())
return false;
base::FilePath result;
if (base::GetTempDir(&result)) {
temp_dir = result.value();
return true;
}
return false;
}
bool CefCreateNewTempDirectory(const CefString& prefix,
CefString& new_temp_path) {
if (!AllowFileIO())
return false;
base::FilePath result;
if (base::CreateNewTempDirectory(prefix, &result)) {
new_temp_path = result.value();
return true;
}
return false;
}
bool CefCreateTempDirectoryInDirectory(const CefString& base_dir,
const CefString& prefix,
CefString& new_dir) {
if (!AllowFileIO())
return false;
base::FilePath result;
if (base::CreateTemporaryDirInDir(base_dir, prefix, &result)) {
new_dir = result.value();
return true;
}
return false;
}
bool CefDirectoryExists(const CefString& path) {
if (!AllowFileIO())
return false;
return base::DirectoryExists(path);
}
bool CefDeleteFile(const CefString& path, bool recursive) {
if (!AllowFileIO())
return false;
return base::DeleteFile(path, recursive);
}
bool CefZipDirectory(const CefString& src_dir,
const CefString& dest_file,
bool include_hidden_files) {
if (!AllowFileIO())
return false;
return zip::Zip(src_dir, dest_file, include_hidden_files);
}

View File

@ -12,6 +12,8 @@
#include "include/cef_app.h"
#include "include/capi/cef_app_capi.h"
#include "include/cef_file_util.h"
#include "include/capi/cef_file_util_capi.h"
#include "include/cef_geolocation.h"
#include "include/capi/cef_geolocation_capi.h"
#include "include/cef_origin_whitelist.h"
@ -387,6 +389,147 @@ CEF_EXPORT void cef_enable_highdpi_support() {
CefEnableHighDPISupport();
}
CEF_EXPORT int cef_create_directory(const cef_string_t* full_path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: full_path; type: string_byref_const
DCHECK(full_path);
if (!full_path)
return 0;
// Execute
bool _retval = CefCreateDirectory(
CefString(full_path));
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_get_temp_directory(cef_string_t* temp_dir) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: temp_dir; type: string_byref
DCHECK(temp_dir);
if (!temp_dir)
return 0;
// Translate param: temp_dir; type: string_byref
CefString temp_dirStr(temp_dir);
// Execute
bool _retval = CefGetTempDirectory(
temp_dirStr);
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_create_new_temp_directory(const cef_string_t* prefix,
cef_string_t* new_temp_path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: new_temp_path; type: string_byref
DCHECK(new_temp_path);
if (!new_temp_path)
return 0;
// Unverified params: prefix
// Translate param: new_temp_path; type: string_byref
CefString new_temp_pathStr(new_temp_path);
// Execute
bool _retval = CefCreateNewTempDirectory(
CefString(prefix),
new_temp_pathStr);
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_create_temp_directory_in_directory(
const cef_string_t* base_dir, const cef_string_t* prefix,
cef_string_t* new_dir) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: base_dir; type: string_byref_const
DCHECK(base_dir);
if (!base_dir)
return 0;
// Verify param: new_dir; type: string_byref
DCHECK(new_dir);
if (!new_dir)
return 0;
// Unverified params: prefix
// Translate param: new_dir; type: string_byref
CefString new_dirStr(new_dir);
// Execute
bool _retval = CefCreateTempDirectoryInDirectory(
CefString(base_dir),
CefString(prefix),
new_dirStr);
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_directory_exists(const cef_string_t* path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: path; type: string_byref_const
DCHECK(path);
if (!path)
return 0;
// Execute
bool _retval = CefDirectoryExists(
CefString(path));
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_delete_file(const cef_string_t* path, int recursive) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: path; type: string_byref_const
DCHECK(path);
if (!path)
return 0;
// Execute
bool _retval = CefDeleteFile(
CefString(path),
recursive?true:false);
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_zip_directory(const cef_string_t* src_dir,
const cef_string_t* dest_file, int include_hidden_files) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: src_dir; type: string_byref_const
DCHECK(src_dir);
if (!src_dir)
return 0;
// Verify param: dest_file; type: string_byref_const
DCHECK(dest_file);
if (!dest_file)
return 0;
// Execute
bool _retval = CefZipDirectory(
CefString(src_dir),
CefString(dest_file),
include_hidden_files?true:false);
// Return type: bool
return _retval;
}
CEF_EXPORT int cef_get_geolocation(
struct _cef_get_geolocation_callback_t* callback) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING

View File

@ -0,0 +1,87 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 2011 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.
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "include/base/cef_logging.h"
#include "include/cef_file_util.h"
CefScopedTempDir::CefScopedTempDir() {
}
CefScopedTempDir::~CefScopedTempDir() {
if (!path_.empty() && !Delete())
DLOG(WARNING) << "Could not delete temp dir in dtor.";
}
bool CefScopedTempDir::CreateUniqueTempDir() {
if (!path_.empty())
return false;
// This "scoped_dir" prefix is only used on Windows and serves as a template
// for the unique name.
if (!CefCreateNewTempDirectory("scoped_dir", path_))
return false;
return true;
}
bool CefScopedTempDir::CreateUniqueTempDirUnderPath(
const CefString& base_path) {
if (!path_.empty())
return false;
// If |base_path| does not exist, create it.
if (!CefCreateDirectory(base_path))
return false;
// Create a new, uniquely named directory under |base_path|.
if (!CefCreateTempDirectoryInDirectory(base_path, "scoped_dir_", path_))
return false;
return true;
}
bool CefScopedTempDir::Set(const CefString& path) {
if (!path_.empty())
return false;
if (!CefDirectoryExists(path) && !CefCreateDirectory(path))
return false;
path_ = path;
return true;
}
bool CefScopedTempDir::Delete() {
if (path_.empty())
return false;
bool ret = CefDeleteFile(path_, true);
if (ret) {
// We only clear the path if deleted the directory.
path_.clear();
}
return ret;
}
CefString CefScopedTempDir::Take() {
CefString ret = path_;
path_.clear();
return ret;
}
const CefString& CefScopedTempDir::GetPath() const {
DCHECK(!path_.empty()) << "Did you call CreateUniqueTempDir* before?";
return path_;
}
bool CefScopedTempDir::IsEmpty() const {
return path_.empty();
}
bool CefScopedTempDir::IsValid() const {
return !path_.empty() && CefDirectoryExists(path_);
}

View File

@ -12,6 +12,8 @@
#include "include/cef_app.h"
#include "include/capi/cef_app_capi.h"
#include "include/cef_file_util.h"
#include "include/capi/cef_file_util_capi.h"
#include "include/cef_geolocation.h"
#include "include/capi/cef_geolocation_capi.h"
#include "include/cef_origin_whitelist.h"
@ -379,6 +381,124 @@ CEF_GLOBAL void CefEnableHighDPISupport() {
cef_enable_highdpi_support();
}
CEF_GLOBAL bool CefCreateDirectory(const CefString& full_path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: full_path; type: string_byref_const
DCHECK(!full_path.empty());
if (full_path.empty())
return false;
// Execute
int _retval = cef_create_directory(
full_path.GetStruct());
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefGetTempDirectory(CefString& temp_dir) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
int _retval = cef_get_temp_directory(
temp_dir.GetWritableStruct());
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefCreateNewTempDirectory(const CefString& prefix,
CefString& new_temp_path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Unverified params: prefix
// Execute
int _retval = cef_create_new_temp_directory(
prefix.GetStruct(),
new_temp_path.GetWritableStruct());
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefCreateTempDirectoryInDirectory(const CefString& base_dir,
const CefString& prefix, CefString& new_dir) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: base_dir; type: string_byref_const
DCHECK(!base_dir.empty());
if (base_dir.empty())
return false;
// Unverified params: prefix
// Execute
int _retval = cef_create_temp_directory_in_directory(
base_dir.GetStruct(),
prefix.GetStruct(),
new_dir.GetWritableStruct());
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefDirectoryExists(const CefString& path) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: path; type: string_byref_const
DCHECK(!path.empty());
if (path.empty())
return false;
// Execute
int _retval = cef_directory_exists(
path.GetStruct());
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefDeleteFile(const CefString& path, bool recursive) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: path; type: string_byref_const
DCHECK(!path.empty());
if (path.empty())
return false;
// Execute
int _retval = cef_delete_file(
path.GetStruct(),
recursive);
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefZipDirectory(const CefString& src_dir,
const CefString& dest_file, bool include_hidden_files) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: src_dir; type: string_byref_const
DCHECK(!src_dir.empty());
if (src_dir.empty())
return false;
// Verify param: dest_file; type: string_byref_const
DCHECK(!dest_file.empty());
if (dest_file.empty())
return false;
// Execute
int _retval = cef_zip_directory(
src_dir.GetStruct(),
dest_file.GetStruct(),
include_hidden_files);
// Return type: bool
return _retval?true:false;
}
CEF_GLOBAL bool CefGetGeolocation(
CefRefPtr<CefGetGeolocationCallback> callback) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING

View File

@ -4,7 +4,6 @@
#include <vector>
#include "base/files/scoped_temp_dir.h"
#include "base/synchronization/waitable_event.h"
#include "include/base/cef_bind.h"
@ -13,12 +12,15 @@
#include "include/cef_cookie.h"
#include "include/cef_scheme.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/test_handler.h"
#include "tests/unittests/test_suite.h"
namespace {
const int kCacheDeleteDelay = 50;
const char* kTestUrl = "http://www.test.com/path/to/cookietest/foo.html";
const char* kTestDomain = "www.test.com";
const char* kTestPath = "/path/to/cookietest";
@ -448,7 +450,7 @@ void TestChangeDirectory(CefRefPtr<CefCookieManager> manager,
const CefString& original_dir) {
CefCookie cookie;
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
// Create a new temporary directory.
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
@ -457,7 +459,7 @@ void TestChangeDirectory(CefRefPtr<CefCookieManager> manager,
DeleteAllCookies(manager, event);
// Set the new temporary directory as the storage location.
EXPECT_TRUE(manager->SetStoragePath(temp_dir.GetPath().value(), false, NULL));
EXPECT_TRUE(manager->SetStoragePath(temp_dir.GetPath(), false, NULL));
// Wait for the storage location change to complete on the IO thread.
WaitForIOThread();
@ -481,7 +483,7 @@ void TestChangeDirectory(CefRefPtr<CefCookieManager> manager,
VerifyNoCookies(manager, event, true);
// Set the new temporary directory as the storage location.
EXPECT_TRUE(manager->SetStoragePath(temp_dir.GetPath().value(), false, NULL));
EXPECT_TRUE(manager->SetStoragePath(temp_dir.GetPath(), false, NULL));
// Wait for the storage location change to complete on the IO thread.
WaitForIOThread();
@ -529,7 +531,7 @@ TEST(CookieTest, DomainCookieInMemory) {
// Test creation of a domain cookie.
TEST(CookieTest, DomainCookieOnDisk) {
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
// Create a new temporary directory.
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
@ -539,7 +541,7 @@ TEST(CookieTest, DomainCookieOnDisk) {
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefRefPtr<CefCookieManager> manager =
CefCookieManager::CreateManager(temp_dir.GetPath().value(), false,
CefCookieManager::CreateManager(temp_dir.GetPath(), false,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -549,7 +551,7 @@ TEST(CookieTest, DomainCookieOnDisk) {
// The backing store will be closed on the DB thread after the CookieManager
// is destroyed.
manager = NULL;
WaitForDBThread();
WaitForDBThreadWithDelay(kCacheDeleteDelay);
}
// Test creation of a host cookie.
@ -583,7 +585,7 @@ TEST(CookieTest, HostCookieInMemory) {
// Test creation of a host cookie.
TEST(CookieTest, HostCookieOnDisk) {
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
// Create a new temporary directory.
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
@ -593,7 +595,7 @@ TEST(CookieTest, HostCookieOnDisk) {
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefRefPtr<CefCookieManager> manager =
CefCookieManager::CreateManager(temp_dir.GetPath().value(), false,
CefCookieManager::CreateManager(temp_dir.GetPath(), false,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -603,7 +605,7 @@ TEST(CookieTest, HostCookieOnDisk) {
// The backing store will be closed on the DB thread after the CookieManager
// is destroyed.
manager = NULL;
WaitForDBThread();
WaitForDBThreadWithDelay(kCacheDeleteDelay);
}
// Test creation of multiple cookies.
@ -637,7 +639,7 @@ TEST(CookieTest, MultipleCookiesInMemory) {
// Test creation of multiple cookies.
TEST(CookieTest, MultipleCookiesOnDisk) {
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
// Create a new temporary directory.
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
@ -647,7 +649,7 @@ TEST(CookieTest, MultipleCookiesOnDisk) {
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefRefPtr<CefCookieManager> manager =
CefCookieManager::CreateManager(temp_dir.GetPath().value(), false,
CefCookieManager::CreateManager(temp_dir.GetPath(), false,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -657,7 +659,7 @@ TEST(CookieTest, MultipleCookiesOnDisk) {
// The backing store will be closed on the DB thread after the CookieManager
// is destroyed.
manager = NULL;
WaitForDBThread();
WaitForDBThreadWithDelay(kCacheDeleteDelay);
}
TEST(CookieTest, AllCookiesGlobal) {
@ -688,7 +690,7 @@ TEST(CookieTest, AllCookiesInMemory) {
}
TEST(CookieTest, AllCookiesOnDisk) {
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
// Create a new temporary directory.
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
@ -698,7 +700,7 @@ TEST(CookieTest, AllCookiesOnDisk) {
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefRefPtr<CefCookieManager> manager =
CefCookieManager::CreateManager(temp_dir.GetPath().value(), false,
CefCookieManager::CreateManager(temp_dir.GetPath(), false,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -708,7 +710,7 @@ TEST(CookieTest, AllCookiesOnDisk) {
// The backing store will be closed on the DB thread after the CookieManager
// is destroyed.
manager = NULL;
WaitForDBThread();
WaitForDBThreadWithDelay(kCacheDeleteDelay);
}
TEST(CookieTest, ChangeDirectoryGlobal) {
@ -742,7 +744,7 @@ TEST(CookieTest, ChangeDirectoryCreated) {
}
TEST(CookieTest, SessionCookieNoPersist) {
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
@ -752,7 +754,7 @@ TEST(CookieTest, SessionCookieNoPersist) {
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
CefRefPtr<CefCookieManager> manager =
CefCookieManager::CreateManager(temp_dir.GetPath().value(), false,
CefCookieManager::CreateManager(temp_dir.GetPath(), false,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -768,7 +770,7 @@ TEST(CookieTest, SessionCookieNoPersist) {
event.Wait();
// Create a new manager to read the same cookie store.
manager = CefCookieManager::CreateManager(temp_dir.GetPath().value(), false,
manager = CefCookieManager::CreateManager(temp_dir.GetPath(), false,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -778,7 +780,7 @@ TEST(CookieTest, SessionCookieNoPersist) {
}
TEST(CookieTest, SessionCookieWillPersist) {
base::ScopedTempDir temp_dir;
CefScopedTempDir temp_dir;
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
@ -788,7 +790,7 @@ TEST(CookieTest, SessionCookieWillPersist) {
EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
CefRefPtr<CefCookieManager> manager =
CefCookieManager::CreateManager(temp_dir.GetPath().value(), true,
CefCookieManager::CreateManager(temp_dir.GetPath(), true,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());
@ -804,7 +806,7 @@ TEST(CookieTest, SessionCookieWillPersist) {
event.Wait();
// Create a new manager to read the same cookie store.
manager = CefCookieManager::CreateManager(temp_dir.GetPath().value(), true,
manager = CefCookieManager::CreateManager(temp_dir.GetPath(), true,
new TestCompletionCallback(&event));
event.Wait();
EXPECT_TRUE(manager.get());

View File

@ -2,12 +2,11 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "include/cef_scheme.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/file_util.h"
#include "tests/unittests/test_handler.h"
namespace {
@ -158,7 +157,7 @@ class DownloadTestHandler : public TestHandler {
// Create a new temporary directory.
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
test_path_ = temp_dir_.GetPath().AppendASCII(kTestFileName);
test_path_ = file_util::JoinPath(temp_dir_.GetPath(), kTestFileName);
if (test_mode_ == NAVIGATED) {
// Add the resource that we'll navigate to.
@ -254,7 +253,7 @@ class DownloadTestHandler : public TestHandler {
download_item->GetContentDisposition().ToString().c_str());
EXPECT_STREQ(kTestMimeType, download_item->GetMimeType().ToString().c_str());
callback->Continue(test_path_.value(), false);
callback->Continue(test_path_, false);
if (test_mode_ == NAVIGATED)
browser->GetMainFrame()->LoadURL(kTestNavUrl);
@ -291,8 +290,7 @@ class DownloadTestHandler : public TestHandler {
std::string full_path = download_item->GetFullPath();
if (!full_path.empty()) {
got_full_path_.yes();
EXPECT_STREQ(CefString(test_path_.value()).ToString().c_str(),
full_path.c_str());
EXPECT_STREQ(test_path_.c_str(), full_path.c_str());
}
if (download_item->IsComplete()) {
@ -315,7 +313,30 @@ class DownloadTestHandler : public TestHandler {
ContinuePendingIfReady();
}
void VerifyResultsOnFileThread() {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
if (test_mode_ != PENDING) {
// Verify the file contents.
std::string contents;
EXPECT_TRUE(file_util::ReadFileToString(test_path_, &contents));
EXPECT_STREQ(kTestContent, contents.c_str());
}
EXPECT_TRUE(temp_dir_.Delete());
EXPECT_TRUE(temp_dir_.IsEmpty());
CefPostTask(TID_UI, base::Bind(&DownloadTestHandler::DestroyTest, this));
}
void DestroyTest() override {
if (!temp_dir_.IsEmpty()) {
// Clean up temp_dir_ on the FILE thread before destroying the test.
CefPostTask(TID_FILE,
base::Bind(&DownloadTestHandler::VerifyResultsOnFileThread, this));
return;
}
CefRegisterSchemeHandlerFactory("http", kTestDomain, NULL);
EXPECT_TRUE(got_download_request_);
@ -333,15 +354,8 @@ class DownloadTestHandler : public TestHandler {
} else {
EXPECT_TRUE(got_download_complete_);
EXPECT_TRUE(got_full_path_);
// Verify the file contents.
std::string contents;
EXPECT_TRUE(base::ReadFileToString(test_path_, &contents));
EXPECT_STREQ(kTestContent, contents.c_str());
}
EXPECT_TRUE(temp_dir_.Delete());
TestHandler::DestroyTest();
}
@ -351,8 +365,8 @@ class DownloadTestHandler : public TestHandler {
// Used with NAVIGATED test mode.
CefRefPtr<CefCallback> delay_callback_;
base::ScopedTempDir temp_dir_;
base::FilePath test_path_;
CefScopedTempDir temp_dir_;
std::string test_path_;
uint32 download_id_;
TrackCallback got_download_request_;

View File

@ -0,0 +1,110 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 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.
#include "tests/unittests/file_util.h"
#include "include/base/cef_build.h"
#include "include/cef_task.h"
#include <algorithm>
#include <cstdio>
#include <memory>
namespace file_util {
namespace {
bool AllowFileIO() {
if (CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)) {
NOTREACHED() << "file IO is not allowed on the current thread";
return false;
}
return true;
}
} // namespace
#if defined(OS_WIN)
const char kPathSep = '\\';
#else
const char kPathSep = '/';
#endif
bool ReadFileToString(const std::string& path, std::string* contents,
size_t max_size) {
if (!AllowFileIO())
return false;
if (contents)
contents->clear();
FILE* file = fopen(path.c_str(), "rb");
if (!file)
return false;
const size_t kBufferSize = 1 << 16;
std::unique_ptr<char[]> buf(new char[kBufferSize]);
size_t len;
size_t size = 0;
bool read_status = true;
// Many files supplied in |path| have incorrect size (proc files etc).
// Hence, the file is read sequentially as opposed to a one-shot read.
while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
if (contents)
contents->append(buf.get(), std::min(len, max_size - size));
if ((max_size - size) < len) {
read_status = false;
break;
}
size += len;
}
read_status = read_status && !ferror(file);
fclose(file);
return read_status;
}
int WriteFile(const std::string& path, const char* data, int size) {
if (!AllowFileIO())
return -1;
FILE* file = fopen(path.c_str(), "wb");
if (!file)
return -1;
int written = 0;
do {
size_t write = fwrite(data + written, 1, size - written, file);
if (write == 0)
break;
written += write;
} while (written < size);
fclose(file);
return written;
}
std::string JoinPath(const std::string& path1, const std::string& path2) {
if (path1.empty() && path2.empty())
return std::string();
if (path1.empty())
return path2;
if (path2.empty())
return path1;
std::string result = path1;
if (result[result.size() - 1] != kPathSep)
result += kPathSep;
if (path2[0] == kPathSep)
result += path2.substr(1);
else
result += path2;
return result;
}
} // namespace file_util

View File

@ -0,0 +1,39 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 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 CEF_TESTS_UNITTESTS_FILE_UTIL_H_
#define CEF_TESTS_UNITTESTS_FILE_UTIL_H_
#pragma once
#include <limits>
#include <string>
namespace file_util {
// Platform-specific path separator.
extern const char kPathSep;
// Reads the file at |path| into |contents| and returns true on success and
// false on error. In case of I/O error, |contents| holds the data that could
// be read from the file before the error occurred. When the file size exceeds
// max_size|, the function returns false with |contents| holding the file
// truncated to |max_size|. |contents| may be NULL, in which case this function
// is useful for its side effect of priming the disk cache (could be used for
// unit tests). Calling this function on the browser process UI or IO threads is
// not allowed.
bool ReadFileToString(const std::string& path, std::string* contents,
size_t max_size = std::numeric_limits<size_t>::max());
// Writes the given buffer into the file, overwriting any data that was
// previously there. Returns the number of bytes written, or -1 on error.
// Calling this function on the browser process UI or IO threads is not allowed.
int WriteFile(const std::string& path, const char* data, int size);
// Combines |path1| and |path2| with the correct platform-specific path
// separator.
std::string JoinPath(const std::string& path1, const std::string& path2);
} // namespace file_util
#endif // CEF_TESTS_UNITTESTS_FILE_UTIL_H_

View File

@ -0,0 +1,47 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 2011 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.
#include <string>
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/file_util.h"
TEST(FileUtil, JoinPath) {
// Should return whichever path component is non-empty.
EXPECT_STREQ("", file_util::JoinPath("", "").c_str());
EXPECT_STREQ("path1", file_util::JoinPath("path1", "").c_str());
EXPECT_STREQ("path2", file_util::JoinPath("", "path2").c_str());
const std::string& expected =
std::string("path1") + file_util::kPathSep + std::string("path2");
// Should always be 1 kPathSep character between paths.
EXPECT_STREQ(expected.c_str(), file_util::JoinPath("path1", "path2").c_str());
EXPECT_STREQ(expected.c_str(),
file_util::JoinPath(std::string("path1") + file_util::kPathSep,
"path2").c_str());
EXPECT_STREQ(expected.c_str(),
file_util::JoinPath("path1",
file_util::kPathSep + std::string("path2")).c_str());
EXPECT_STREQ(expected.c_str(),
file_util::JoinPath(std::string("path1") + file_util::kPathSep,
file_util::kPathSep + std::string("path2")).c_str());
}
TEST(FileUtil, WriteAndReadFile) {
CefScopedTempDir dir;
EXPECT_TRUE(dir.CreateUniqueTempDir());
const std::string& data = "Test contents to read/write";
const std::string& path = file_util::JoinPath(dir.GetPath(), "test.txt");
EXPECT_EQ(static_cast<int>(data.size()),
file_util::WriteFile(path.c_str(), data.data(),
static_cast<int>(data.size())));
std::string read;
EXPECT_TRUE(file_util::ReadFileToString(path.c_str(), &read));
EXPECT_STREQ(data.c_str(), read.c_str());
}

View File

@ -3,10 +3,10 @@
// can be found in the LICENSE file.
#include "include/base/cef_bind.h"
#include "base/files/scoped_temp_dir.h"
#include "include/cef_request_context.h"
#include "include/cef_request_context_handler.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/test_handler.h"
@ -172,11 +172,11 @@ TEST(RequestContextTest, CreateContextSharedGlobal) {
}
TEST(RequestContextTest, CreateContextSharedOnDisk) {
base::ScopedTempDir tempdir;
CefScopedTempDir tempdir;
EXPECT_TRUE(tempdir.CreateUniqueTempDir());
CefRequestContextSettings settings;
CefString(&settings.cache_path) = tempdir.GetPath().value();
CefString(&settings.cache_path) = tempdir.GetPath();
CefRefPtr<CefRequestContext> context1 =
CefRequestContext::CreateContext(settings, NULL);

View File

@ -4,16 +4,15 @@
#include <vector>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "include/base/cef_bind.h"
#include "include/cef_file_util.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_resource_manager.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "include/wrapper/cef_stream_resource_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/file_util.h"
#include "tests/unittests/routing_test_handler.h"
#include "third_party/zlib/google/zip.h"
namespace {
@ -29,9 +28,10 @@ std::string CreateContents(const std::string& message) {
"</script></html></body>";
}
void WriteFile(const base::FilePath& path, const std::string& contents) {
void WriteFile(const std::string& path, const std::string& contents) {
int contents_size = static_cast<int>(contents.size());
int write_ct = base::WriteFile(path, contents.data(), contents_size);
int write_ct =
file_util::WriteFile(path, contents.data(), contents_size);
EXPECT_EQ(contents_size, write_ct);
}
@ -689,22 +689,23 @@ TEST(ResourceManagerTest, DirectoryProvider) {
state.urls_.push_back(kUrlBase + std::string("/sub/") + kFile3);
state.urls_.push_back(kUrlBase + std::string("/") + kFile4);
base::ScopedTempDir scoped_dir;
CefScopedTempDir scoped_dir;
EXPECT_TRUE(scoped_dir.CreateUniqueTempDir());
// Write the files to disk.
const base::FilePath& temp_dir = scoped_dir.GetPath();
WriteFile(temp_dir.AppendASCII(kFile1), CreateContents(success1_message));
WriteFile(temp_dir.AppendASCII(kFile2), CreateContents(success2_message));
const std::string& temp_dir = scoped_dir.GetPath();
WriteFile(file_util::JoinPath(temp_dir, kFile1),
CreateContents(success1_message));
WriteFile(file_util::JoinPath(temp_dir, kFile2),
CreateContents(success2_message));
// Also include a subdirectory.
const base::FilePath& sub_dir = temp_dir.AppendASCII("sub");
EXPECT_TRUE(base::CreateDirectory(sub_dir));
WriteFile(sub_dir.AppendASCII(kFile3), CreateContents(success3_message));
const std::string& sub_dir = file_util::JoinPath(temp_dir, "sub");
EXPECT_TRUE(CefCreateDirectory(sub_dir));
WriteFile(file_util::JoinPath(sub_dir, kFile3),
CreateContents(success3_message));
state.manager_->AddDirectoryProvider(kUrlBase,
CefString(temp_dir.value()),
0, std::string());
state.manager_->AddDirectoryProvider(kUrlBase, temp_dir, 0, std::string());
CefRefPtr<ResourceManagerTestHandler> handler =
new ResourceManagerTestHandler(&state);
@ -747,30 +748,32 @@ TEST(ResourceManagerTest, ArchiveProvider) {
state.urls_.push_back(kUrlBase + std::string("/") + kFile4);
// Only the first 2 URLs will be handled.
base::ScopedTempDir scoped_dir;
CefScopedTempDir scoped_dir;
EXPECT_TRUE(scoped_dir.CreateUniqueTempDir());
const base::FilePath& temp_dir = scoped_dir.GetPath();
const std::string& temp_dir = scoped_dir.GetPath();
// Write the files to disk.
const base::FilePath& file_dir = temp_dir.AppendASCII("files");
EXPECT_TRUE(base::CreateDirectory(file_dir));
WriteFile(file_dir.AppendASCII(kFile1), CreateContents(success1_message));
WriteFile(file_dir.AppendASCII(kFile2), CreateContents(success2_message));
const std::string& file_dir = file_util::JoinPath(temp_dir, "files");
EXPECT_TRUE(CefCreateDirectory(file_dir));
WriteFile(file_util::JoinPath(file_dir, kFile1),
CreateContents(success1_message));
WriteFile(file_util::JoinPath(file_dir, kFile2),
CreateContents(success2_message));
// Also include a subdirectory.
const base::FilePath& sub_dir = file_dir.AppendASCII("sub");
EXPECT_TRUE(base::CreateDirectory(sub_dir));
WriteFile(sub_dir.AppendASCII(kFile3), CreateContents(success3_message));
const std::string& sub_dir = file_util::JoinPath(file_dir, "sub");
EXPECT_TRUE(CefCreateDirectory(sub_dir));
WriteFile(file_util::JoinPath(sub_dir, kFile3),
CreateContents(success3_message));
const base::FilePath& archive_path = temp_dir.AppendASCII("archive.zip");
const std::string& archive_path =
file_util::JoinPath(temp_dir, "archive.zip");
// Create the archive file.
EXPECT_TRUE(zip::Zip(file_dir, archive_path, false));
EXPECT_TRUE(CefZipDirectory(file_dir, archive_path, false));
state.manager_->AddArchiveProvider(kUrlBase,
CefString(archive_path.value()),
std::string(),
state.manager_->AddArchiveProvider(kUrlBase, archive_path, std::string(),
0, std::string());
CefRefPtr<ResourceManagerTestHandler> handler =

View File

@ -0,0 +1,90 @@
// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright
// 2011 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.
#include <string>
#include "include/cef_file_util.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(ScopedTempDir, FullPath) {
CefString test_path;
CefCreateNewTempDirectory("scoped_temp_dir", test_path);
// Against an existing dir, it should get destroyed when leaving scope.
EXPECT_TRUE(CefDirectoryExists(test_path));
{
CefScopedTempDir dir;
EXPECT_TRUE(dir.Set(test_path));
EXPECT_TRUE(dir.IsValid());
}
EXPECT_FALSE(CefDirectoryExists(test_path));
{
CefScopedTempDir dir;
EXPECT_TRUE(dir.Set(test_path));
// Now the dir doesn't exist, so ensure that it gets created.
EXPECT_TRUE(CefDirectoryExists(test_path));
// When we call Take(), it shouldn't get destroyed when leaving scope.
CefString path = dir.Take();
EXPECT_STREQ(path.ToString().c_str(), test_path.ToString().c_str());
EXPECT_FALSE(dir.IsValid());
}
EXPECT_TRUE(CefDirectoryExists(test_path));
// Clean up.
{
CefScopedTempDir dir;
EXPECT_TRUE(dir.Set(test_path));
}
EXPECT_FALSE(CefDirectoryExists(test_path));
}
TEST(ScopedTempDir, TempDir) {
// In this case, just verify that a directory was created and that it's a
// child of TempDir.
CefString test_path;
{
CefScopedTempDir dir;
EXPECT_TRUE(dir.CreateUniqueTempDir());
test_path = dir.GetPath();
EXPECT_TRUE(CefDirectoryExists(test_path));
CefString tmp_dir;
EXPECT_TRUE(CefGetTempDirectory(tmp_dir));
EXPECT_TRUE(test_path.ToString().find(tmp_dir.ToString()) !=
std::string::npos);
}
EXPECT_FALSE(CefDirectoryExists(test_path));
}
TEST(ScopedTempDir, UniqueTempDirUnderPath) {
// Create a path which will contain a unique temp path.
CefString base_path;
ASSERT_TRUE(CefCreateNewTempDirectory("base_dir", base_path));
CefString test_path;
{
CefScopedTempDir dir;
EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path));
test_path = dir.GetPath();
EXPECT_TRUE(CefDirectoryExists(test_path));
EXPECT_TRUE(test_path.ToString().find(base_path.ToString()) == 0);
}
EXPECT_FALSE(CefDirectoryExists(test_path));
CefDeleteFile(base_path, true);
}
TEST(ScopedTempDir, MultipleInvocations) {
CefScopedTempDir dir;
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
EXPECT_TRUE(dir.Delete());
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
CefScopedTempDir other_dir;
EXPECT_TRUE(other_dir.Set(dir.Take()));
EXPECT_TRUE(dir.CreateUniqueTempDir());
EXPECT_FALSE(dir.CreateUniqueTempDir());
EXPECT_FALSE(other_dir.CreateUniqueTempDir());
}

View File

@ -10,19 +10,20 @@ void SignalEvent(base::WaitableEvent* event) {
event->Signal();
}
void WaitForThread(CefThreadId thread_id) {
void WaitForThread(CefThreadId thread_id, int64 delay_ms) {
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefPostTask(thread_id, base::Bind(SignalEvent, &event));
CefPostDelayedTask(thread_id, base::Bind(SignalEvent, &event), delay_ms);
event.Wait();
}
void WaitForThread(CefRefPtr<CefTaskRunner> task_runner) {
void WaitForThread(CefRefPtr<CefTaskRunner> task_runner, int64 delay_ms) {
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
task_runner->PostTask(CefCreateClosureTask(base::Bind(SignalEvent, &event)));
task_runner->PostDelayedTask(
CefCreateClosureTask(base::Bind(SignalEvent, &event)), delay_ms);
event.Wait();
}

View File

@ -16,12 +16,15 @@ void SignalEvent(base::WaitableEvent* event);
// Post a task to the specified thread and wait for the task to execute as
// indication that all previously pending tasks on that thread have completed.
void WaitForThread(CefThreadId thread_id);
void WaitForThread(CefRefPtr<CefTaskRunner> task_runner);
void WaitForThread(CefThreadId thread_id, int64 delay_ms = 0);
void WaitForThread(CefRefPtr<CefTaskRunner> task_runner, int64 delay_ms = 0);
#define WaitForIOThread() WaitForThread(TID_IO)
#define WaitForUIThread() WaitForThread(TID_UI)
#define WaitForDBThread() WaitForThread(TID_DB)
#define WaitForIOThreadWithDelay(delay_ms) WaitForThread(TID_IO, delay_ms)
#define WaitForUIThreadWithDelay(delay_ms) WaitForThread(TID_UI, delay_ms)
#define WaitForDBThreadWithDelay(delay_ms) WaitForThread(TID_DB, delay_ms)
// Assert that execution is occuring on the named thread.
#define EXPECT_UI_THREAD() EXPECT_TRUE(CefCurrentlyOn(TID_UI));

View File

@ -2,14 +2,15 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "base/files/file_util.h"
#include "base/synchronization/waitable_event.h"
#include "include/base/cef_bind.h"
#include "include/cef_file_util.h"
#include "include/cef_task.h"
#include "include/cef_trace.h"
#include "include/wrapper/cef_closure_task.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/unittests/file_util.h"
#include "tests/unittests/test_handler.h"
// Use the CEF version of the TRACE_* macros instead of the Chromium version.
@ -80,11 +81,11 @@ class TracingTestHandler : public CefEndTracingCallback,
type_(type) {
}
void ReadTracingFile(const base::FilePath& file_path) {
void ReadTracingFile(const std::string& file_path) {
EXPECT_FILE_THREAD();
base::ReadFileToString(file_path, &trace_data_);
base::DeleteFile(file_path, false);
EXPECT_TRUE(file_util::ReadFileToString(file_path, &trace_data_));
EXPECT_TRUE(CefDeleteFile(file_path, false));
completion_event_.Signal();
}
@ -93,13 +94,8 @@ class TracingTestHandler : public CefEndTracingCallback,
void OnEndTracingComplete(const CefString& tracing_file) override {
EXPECT_UI_THREAD();
#if defined(OS_WIN)
base::FilePath file_path(tracing_file.ToWString());
#else
base::FilePath file_path(tracing_file.ToString());
#endif
CefPostTask(TID_FILE,
base::Bind(&TracingTestHandler::ReadTracingFile, this, file_path));
base::Bind(&TracingTestHandler::ReadTracingFile, this, tracing_file));
}
void RunTracing() {

View File

@ -5,8 +5,6 @@
#include <map>
#include <sstream>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/synchronization/waitable_event.h"
#include "include/base/cef_bind.h"
@ -14,8 +12,10 @@
#include "include/cef_task.h"
#include "include/cef_urlrequest.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_scoped_temp_dir.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "tests/cefclient/renderer/client_app_renderer.h"
#include "tests/unittests/file_util.h"
#include "tests/unittests/test_handler.h"
#include "tests/unittests/test_suite.h"
#include "tests/unittests/test_util.h"
@ -118,10 +118,10 @@ void SetUploadData(CefRefPtr<CefRequest> request,
}
void SetUploadFile(CefRefPtr<CefRequest> request,
const base::FilePath& file) {
const std::string& file) {
CefRefPtr<CefPostData> postData = CefPostData::Create();
CefRefPtr<CefPostDataElement> element = CefPostDataElement::Create();
element->SetToFile(file.value());
element->SetToFile(file);
postData->AddElement(element);
request->SetPostData(postData);
}
@ -144,16 +144,20 @@ void GetUploadData(CefRefPtr<CefRequest> request,
}
// Set a cookie so that we can test if it's sent with the request.
void SetTestCookie(CefRefPtr<CefRequestContext> request_context,
base::WaitableEvent* event) {
void SetTestCookie(CefRefPtr<CefRequestContext> request_context) {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
class Callback : public CefSetCookieCallback {
public:
explicit Callback(base::WaitableEvent* event)
: event_(event) {}
: event_(event) {
EXPECT_TRUE(event_);
}
void OnComplete(bool success) override {
EXPECT_TRUE(success);
event_->Signal();
event_ = nullptr;
}
private:
@ -162,6 +166,10 @@ void SetTestCookie(CefRefPtr<CefRequestContext> request_context,
IMPLEMENT_REFCOUNTING(Callback);
};
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefCookie cookie;
CefString(&cookie.name) = kRequestSendCookieName;
CefString(&cookie.value) = "send-cookie-value";
@ -169,22 +177,25 @@ void SetTestCookie(CefRefPtr<CefRequestContext> request_context,
CefString(&cookie.path) = "/";
cookie.has_expires = false;
EXPECT_TRUE(request_context->GetDefaultCookieManager(NULL)->SetCookie(
kRequestOrigin, cookie, new Callback(event)));
kRequestOrigin, cookie, new Callback(&event)));
// Wait for the Callback.
event->Wait();
event.TimedWait(base::TimeDelta::FromSeconds(2));
EXPECT_TRUE(event.IsSignaled());
}
// Tests if the save cookie has been set. If set, it will be deleted at the same
// time.
void GetTestCookie(CefRefPtr<CefRequestContext> request_context,
base::WaitableEvent* event,
bool* cookie_exists) {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
class Visitor : public CefCookieVisitor {
public:
Visitor(base::WaitableEvent* event, bool* cookie_exists)
: event_(event),
cookie_exists_(cookie_exists) {
EXPECT_TRUE(event_);
}
~Visitor() override {
event_->Signal();
@ -208,13 +219,18 @@ void GetTestCookie(CefRefPtr<CefRequestContext> request_context,
IMPLEMENT_REFCOUNTING(Visitor);
};
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
CefRefPtr<CefCookieManager> cookie_manager =
request_context->GetDefaultCookieManager(NULL);
cookie_manager->VisitUrlCookies(
kRequestOrigin, true, new Visitor(event, cookie_exists));
kRequestOrigin, true, new Visitor(&event, cookie_exists));
// Wait for the Visitor.
event->Wait();
event.TimedWait(base::TimeDelta::FromSeconds(2));
EXPECT_TRUE(event.IsSignaled());
}
@ -554,12 +570,18 @@ class RequestClient : public CefURLRequestClient {
// Executes the tests.
class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
public:
typedef base::Callback<void(void)> TestCallback;
typedef base::Callback<void(const base::Closure&)> TestCallback;
// Delegate methods will be called on the same thread that constructed the
// RequestTestRunner object.
class Delegate {
public:
// Used to notify the handler when the test can be destroyed.
virtual void DestroyTest(const RequestRunSettings& settings) =0;
// Setup has completed.
virtual void OnRunnerSetupComplete() =0;
// Run has completed.
virtual void OnRunnerRunComplete() =0;
protected:
virtual ~Delegate() {}
};
@ -568,6 +590,10 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
bool is_browser_process)
: delegate_(delegate),
is_browser_process_(is_browser_process) {
owner_task_runner_ = CefTaskRunner::GetForCurrentThread();
EXPECT_TRUE(owner_task_runner_.get());
EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
// Helper macro for registering test callbacks.
#define REGISTER_TEST(test_mode, setup_method, run_method) \
RegisterTest(test_mode, \
@ -588,6 +614,11 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
REGISTER_TEST(REQTEST_HEAD, SetupHeadTest, GenericRunTest);
}
void Destroy() {
owner_task_runner_ = nullptr;
request_context_ = nullptr;
}
// Called in the browser process to set the request context that will be used
// when creating the URL request.
void SetRequestContext(CefRefPtr<CefRequestContext> request_context) {
@ -599,30 +630,55 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
// Called in both the browser and render process to setup the test.
void SetupTest(RequestTestMode test_mode) {
EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
const base::Closure& complete_callback =
base::Bind(&RequestTestRunner::SetupComplete, this);
TestMap::const_iterator it = test_map_.find(test_mode);
if (it != test_map_.end()) {
it->second.setup.Run();
AddSchemeHandler();
it->second.setup.Run(
base::Bind(&RequestTestRunner::SetupContinue, this,
complete_callback));
} else {
// Unknown test.
ADD_FAILURE();
complete_callback.Run();
}
}
// Called in either the browser or render process to run the test.
void RunTest(RequestTestMode test_mode) {
EXPECT_TRUE(owner_task_runner_->BelongsToCurrentThread());
const base::Closure& complete_callback =
base::Bind(&RequestTestRunner::RunComplete, this);
TestMap::const_iterator it = test_map_.find(test_mode);
if (it != test_map_.end()) {
it->second.run.Run();
it->second.run.Run(complete_callback);
} else {
// Unknown test.
ADD_FAILURE();
DestroyTest();
complete_callback.Run();
}
}
private:
void SetupGetTest() {
// Continued after |settings_| is populated for the test.
void SetupContinue(const base::Closure& complete_callback) {
if (!owner_task_runner_->BelongsToCurrentThread()) {
owner_task_runner_->PostTask(CefCreateClosureTask(
base::Bind(&RequestTestRunner::SetupContinue, this,
complete_callback)));
return;
}
if (is_browser_process_)
AddSchemeHandler();
complete_callback.Run();
}
void SetupGetTestShared() {
settings_.request = CefRequest::Create();
settings_.request->SetURL(MakeSchemeURL("GetTest.html"));
settings_.request->SetMethod("GET");
@ -635,30 +691,39 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
settings_.response_data = "GET TEST SUCCESS";
}
void SetupGetNoDataTest() {
void SetupGetTest(const base::Closure& complete_callback) {
SetupGetTestShared();
complete_callback.Run();
}
void SetupGetNoDataTest(const base::Closure& complete_callback) {
// Start with the normal get test.
SetupGetTest();
SetupGetTestShared();
// Disable download data notifications.
settings_.request->SetFlags(UR_FLAG_NO_DOWNLOAD_DATA);
settings_.expect_download_data = false;
complete_callback.Run();
}
void SetupGetAllowCookiesTest() {
void SetupGetAllowCookiesTest(const base::Closure& complete_callback) {
// Start with the normal get test.
SetupGetTest();
SetupGetTestShared();
// Send cookies.
settings_.request->SetFlags(UR_FLAG_ALLOW_CACHED_CREDENTIALS);
settings_.expect_save_cookie = true;
settings_.expect_send_cookie = true;
complete_callback.Run();
}
void SetupGetRedirectTest() {
void SetupGetRedirectTest(const base::Closure& complete_callback) {
// Start with the normal get test.
SetupGetTest();
SetupGetTestShared();
// Add a redirect request.
settings_.redirect_request = CefRequest::Create();
@ -673,9 +738,11 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
CefResponse::HeaderMap headerMap;
headerMap.insert(std::make_pair("Location", settings_.request->GetURL()));
settings_.redirect_response->SetHeaderMap(headerMap);
complete_callback.Run();
}
void SetupGetReferrerTest() {
void SetupGetReferrerTest(const base::Closure& complete_callback) {
settings_.request = CefRequest::Create();
settings_.request->SetURL(MakeSchemeURL("GetTest.html"));
settings_.request->SetMethod("GET");
@ -692,9 +759,11 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
settings_.response->SetStatusText("OK");
settings_.response_data = "GET TEST SUCCESS";
complete_callback.Run();
}
void SetupPostTest() {
void SetupPostTestShared() {
settings_.request = CefRequest::Create();
settings_.request->SetURL(MakeSchemeURL("PostTest.html"));
settings_.request->SetMethod("POST");
@ -708,38 +777,58 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
settings_.response_data = "POST TEST SUCCESS";
}
void SetupPostFileTest() {
void SetupPostTest(const base::Closure& complete_callback) {
SetupPostTestShared();
complete_callback.Run();
}
void SetupPostFileTest(const base::Closure& complete_callback) {
// This test is only supported in the browser process.
EXPECT_TRUE(is_browser_process_);
settings_.request = CefRequest::Create();
settings_.request->SetURL(MakeSchemeURL("PostFileTest.html"));
settings_.request->SetMethod("POST");
EXPECT_TRUE(post_file_tmpdir_.CreateUniqueTempDir());
const base::FilePath& path =
post_file_tmpdir_.GetPath().Append(FILE_PATH_LITERAL("example.txt"));
const char content[] = "HELLO FRIEND!";
int write_ct = base::WriteFile(path, content, sizeof(content) - 1);
EXPECT_EQ(static_cast<int>(sizeof(content) - 1), write_ct);
SetUploadFile(settings_.request, path);
settings_.response = CefResponse::Create();
settings_.response->SetMimeType("text/html");
settings_.response->SetStatus(200);
settings_.response->SetStatusText("OK");
settings_.response_data = "POST TEST SUCCESS";
CefPostTask(TID_FILE,
base::Bind(&RequestTestRunner::SetupPostFileTestContinue, this,
complete_callback));
}
void SetupPostWithProgressTest() {
void SetupPostFileTestContinue(const base::Closure& complete_callback) {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
EXPECT_TRUE(post_file_tmpdir_.CreateUniqueTempDir());
const std::string& path =
file_util::JoinPath(post_file_tmpdir_.GetPath(), "example.txt");
const char content[] = "HELLO FRIEND!";
int write_ct = file_util::WriteFile(path, content, sizeof(content) - 1);
EXPECT_EQ(static_cast<int>(sizeof(content) - 1), write_ct);
SetUploadFile(settings_.request, path);
complete_callback.Run();
}
void SetupPostWithProgressTest(const base::Closure& complete_callback) {
// Start with the normal post test.
SetupPostTest();
SetupPostTestShared();
// Enable upload progress notifications.
settings_.request->SetFlags(UR_FLAG_REPORT_UPLOAD_PROGRESS);
settings_.expect_upload_progress = true;
complete_callback.Run();
}
void SetupHeadTest() {
void SetupHeadTest(const base::Closure& complete_callback) {
settings_.request = CefRequest::Create();
settings_.request->SetURL(MakeSchemeURL("HeadTest.html"));
settings_.request->SetMethod("HEAD");
@ -754,34 +843,37 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
settings_.expect_download_progress = false;
settings_.expect_download_data = false;
complete_callback.Run();
}
// Generic test runner.
void GenericRunTest() {
void GenericRunTest(const base::Closure& complete_callback) {
class Test : public RequestClient::Delegate {
public:
Test(scoped_refptr<RequestTestRunner> runner,
const RequestRunSettings& settings)
: runner_(runner),
settings_(settings) {
Test(const RequestRunSettings& settings,
const base::Closure& complete_callback)
: settings_(settings),
complete_callback_(complete_callback) {
EXPECT_FALSE(complete_callback_.is_null());
}
void OnRequestComplete(CefRefPtr<RequestClient> client) override {
CefRefPtr<CefRequest> expected_request;
CefRefPtr<CefResponse> expected_response;
if (runner_->settings_.redirect_request.get())
expected_request = runner_->settings_.redirect_request;
if (settings_.redirect_request.get())
expected_request = settings_.redirect_request;
else
expected_request = runner_->settings_.request;
expected_request = settings_.request;
if (runner_->settings_.redirect_response.get() &&
!runner_->settings_.expect_follow_redirect) {
if (settings_.redirect_response.get() &&
!settings_.expect_follow_redirect) {
// A redirect response was sent but the redirect is not expected to be
// followed.
expected_response = runner_->settings_.redirect_response;
expected_response = settings_.redirect_response;
} else {
expected_response = runner_->settings_.response;
expected_response = settings_.response;
}
TestRequestEqual(expected_request, client->request_, false);
@ -805,7 +897,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
if (settings_.expect_download_progress) {
EXPECT_LE(1, client->download_progress_ct_);
EXPECT_EQ(runner_->settings_.response_data.size(),
EXPECT_EQ(settings_.response_data.size(),
client->download_total_);
} else {
EXPECT_EQ(0, client->download_progress_ct_);
@ -814,19 +906,20 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
if (settings_.expect_download_data) {
EXPECT_LE(1, client->download_data_ct_);
EXPECT_STREQ(runner_->settings_.response_data.c_str(),
EXPECT_STREQ(settings_.response_data.c_str(),
client->download_data_.c_str());
} else {
EXPECT_EQ(0, client->download_data_ct_);
EXPECT_TRUE(client->download_data_.empty());
}
runner_->DestroyTest();
complete_callback_.Run();
complete_callback_.Reset();
}
private:
scoped_refptr<RequestTestRunner> runner_;
RequestRunSettings settings_;
base::Closure complete_callback_;
};
CefRefPtr<CefRequest> request;
@ -837,7 +930,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
EXPECT_TRUE(request.get());
CefRefPtr<RequestClient> client =
new RequestClient(new Test(this, settings_));
new RequestClient(new Test(settings_, complete_callback));
CefURLRequest::Create(request, client.get(), request_context_);
}
@ -850,19 +943,56 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
test_map_.insert(std::make_pair(test_mode, entry));
}
void SetupComplete() {
if (!owner_task_runner_->BelongsToCurrentThread()) {
owner_task_runner_->PostTask(CefCreateClosureTask(
base::Bind(&RequestTestRunner::SetupComplete, this)));
return;
}
delegate_->OnRunnerSetupComplete();
}
// Destroy the current test. Called when the test is complete.
void DestroyTest() {
void RunComplete() {
if (!post_file_tmpdir_.IsEmpty()) {
EXPECT_TRUE(is_browser_process_);
CefPostTask(TID_FILE,
base::Bind(&RequestTestRunner::RunCompleteDeleteTempDirectory, this));
return;
}
// Continue with test completion.
RunCompleteContinue();
}
void RunCompleteDeleteTempDirectory() {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
EXPECT_TRUE(post_file_tmpdir_.Delete());
EXPECT_TRUE(post_file_tmpdir_.IsEmpty());
// Continue with test completion.
RunCompleteContinue();
}
void RunCompleteContinue() {
if (!owner_task_runner_->BelongsToCurrentThread()) {
owner_task_runner_->PostTask(CefCreateClosureTask(
base::Bind(&RequestTestRunner::RunCompleteContinue, this)));
return;
}
if (scheme_factory_.get()) {
EXPECT_TRUE(is_browser_process_);
// Remove the factory registration.
request_context_->RegisterSchemeHandlerFactory(
kRequestScheme, kRequestHost, NULL);
scheme_factory_ = NULL;
}
if (post_file_tmpdir_.IsValid())
EXPECT_TRUE(post_file_tmpdir_.Delete());
delegate_->DestroyTest(settings_);
delegate_->OnRunnerRunComplete();
}
// Return an appropriate scheme URL for the specified |path|.
@ -875,8 +1005,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
// Add a scheme handler for the current test. Called during test setup.
void AddSchemeHandler() {
// Scheme handlers are only registered in the browser process.
if (!is_browser_process_)
return;
EXPECT_TRUE(is_browser_process_);
if (!scheme_factory_.get()) {
// Add the factory registration.
@ -898,6 +1027,12 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
Delegate* delegate_;
bool is_browser_process_;
// Primary thread runner for the object that owns us. In the browser process
// this will be the UI thread and in the renderer process this will be the
// RENDERER thread.
CefRefPtr<CefTaskRunner> owner_task_runner_;
CefRefPtr<CefRequestContext> request_context_;
struct TestEntry {
@ -910,7 +1045,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
std::string scheme_name_;
CefRefPtr<RequestSchemeHandlerFactory> scheme_factory_;
base::ScopedTempDir post_file_tmpdir_;
CefScopedTempDir post_file_tmpdir_;
public:
RequestRunSettings settings_;
@ -920,8 +1055,7 @@ class RequestTestRunner : public base::RefCountedThreadSafe<RequestTestRunner> {
class RequestRendererTest : public ClientAppRenderer::Delegate,
public RequestTestRunner::Delegate {
public:
RequestRendererTest()
: test_runner_(new RequestTestRunner(this, false)) {
RequestRendererTest() {
}
bool OnProcessMessageReceived(
@ -930,18 +1064,20 @@ class RequestRendererTest : public ClientAppRenderer::Delegate,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message) override {
if (message->GetName() == kRequestTestMsg) {
EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
app_ = app;
browser_ = browser;
RequestTestMode test_mode =
test_mode_ =
static_cast<RequestTestMode>(message->GetArgumentList()->GetInt(0));
test_runner_ = new RequestTestRunner(this, false);
// Setup the test. This will create the objects that we test against but
// not register any scheme handlers (because we're in the render process).
test_runner_->SetupTest(test_mode);
test_runner_->SetupTest(test_mode_);
// Run the test.
test_runner_->RunTest(test_mode);
return true;
}
@ -949,9 +1085,18 @@ class RequestRendererTest : public ClientAppRenderer::Delegate,
return false;
}
protected:
private:
void OnRunnerSetupComplete() override {
EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
// Run the test.
test_runner_->RunTest(test_mode_);
}
// Return from the test.
void DestroyTest(const RequestRunSettings& settings) override {
void OnRunnerRunComplete() override {
EXPECT_TRUE(CefCurrentlyOn(TID_RENDERER));
// Check if the test has failed.
bool result = !TestFailed();
@ -967,6 +1112,7 @@ class RequestRendererTest : public ClientAppRenderer::Delegate,
CefRefPtr<ClientAppRenderer> app_;
CefRefPtr<CefBrowser> browser_;
RequestTestMode test_mode_;
scoped_refptr<RequestTestRunner> test_runner_;
@ -977,9 +1123,6 @@ class RequestRendererTest : public ClientAppRenderer::Delegate,
class RequestTestHandler : public TestHandler,
public RequestTestRunner::Delegate {
public:
// Don't hide the DestroyTest method.
using TestHandler::DestroyTest;
RequestTestHandler(RequestTestMode test_mode,
ContextTestMode context_mode,
bool test_in_browser,
@ -987,11 +1130,40 @@ class RequestTestHandler : public TestHandler,
: test_mode_(test_mode),
context_mode_(context_mode),
test_in_browser_(test_in_browser),
test_url_(test_url),
test_runner_(new RequestTestRunner(this, true)) {
test_url_(test_url) {
}
void RunTest() override {
// Time out the test after a reasonable period of time.
SetTestTimeout();
// Start pre-setup actions.
PreSetupStart();
}
void PreSetupStart() {
CefPostTask(TID_FILE,
base::Bind(&RequestTestHandler::PreSetupFileTasks, this));
}
void PreSetupFileTasks() {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
if (context_mode_ == CONTEXT_ONDISK) {
EXPECT_TRUE(context_tmpdir_.CreateUniqueTempDir());
context_tmpdir_path_ = context_tmpdir_.GetPath();
EXPECT_FALSE(context_tmpdir_path_.empty());
}
CefPostTask(TID_UI,
base::Bind(&RequestTestHandler::PreSetupContinue, this));
}
void PreSetupContinue() {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
test_runner_ = new RequestTestRunner(this, true);
// Get or create the request context.
if (context_mode_ == CONTEXT_GLOBAL) {
CefRefPtr<CefRequestContext> request_context =
@ -999,8 +1171,7 @@ class RequestTestHandler : public TestHandler,
EXPECT_TRUE(request_context.get());
test_runner_->SetRequestContext(request_context);
// Continue the test now.
RunTestContinue();
PreSetupComplete();
} else {
// Don't end the test until the temporary request context has been
// destroyed.
@ -1009,8 +1180,8 @@ class RequestTestHandler : public TestHandler,
CefRequestContextSettings settings;
if (context_mode_ == CONTEXT_ONDISK) {
EXPECT_TRUE(context_tmpdir_.CreateUniqueTempDir());
CefString(&settings.cache_path) = context_tmpdir_.GetPath().value();
EXPECT_FALSE(context_tmpdir_.IsEmpty());
CefString(&settings.cache_path) = context_tmpdir_path_;
}
// Create a new temporary request context.
@ -1026,25 +1197,47 @@ class RequestTestHandler : public TestHandler,
// Continue the test once supported schemes has been set.
request_context->GetDefaultCookieManager(NULL)->SetSupportedSchemes(
supported_schemes, new SupportedSchemesCompletionCallback(this));
supported_schemes,
new SupportedSchemesCompletionCallback(
base::Bind(&RequestTestHandler::PreSetupComplete, this)));
}
}
void RunTestContinue() {
void PreSetupComplete() {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI,
base::Bind(&RequestTestHandler::RunTestContinue, this));
base::Bind(&RequestTestHandler::PreSetupComplete, this));
return;
}
// Setup the test. This will create the objects that we test against and
// register any scheme handlers.
test_runner_->SetupTest(test_mode_);
}
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
SetTestCookie(test_runner_->GetRequestContext(), &event);
// Browser process setup is complete.
void OnRunnerSetupComplete() override {
// Start post-setup actions.
PostSetupStart();
}
void PostSetupStart() {
CefPostTask(TID_FILE,
base::Bind(&RequestTestHandler::PostSetupFileTasks, this));
}
void PostSetupFileTasks() {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
// Don't use WaitableEvent on the UI thread.
SetTestCookie(test_runner_->GetRequestContext());
CefPostTask(TID_UI,
base::Bind(&RequestTestHandler::PostSetupComplete, this));
}
void PostSetupComplete() {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
if (test_in_browser_) {
// Run the test now.
@ -1056,9 +1249,6 @@ class RequestTestHandler : public TestHandler,
// Create a browser to run the test in the renderer process.
CreateBrowser(test_url_, test_runner_->GetRequestContext());
}
// Time out the test after a reasonable period of time.
SetTestTimeout();
}
void OnLoadEnd(CefRefPtr<CefBrowser> browser,
@ -1090,21 +1280,39 @@ class RequestTestHandler : public TestHandler,
if (message->GetArgumentList()->GetBool(0))
got_success_.yes();
// Test is complete.
DestroyTest(test_runner_->settings_);
// Renderer process test is complete.
PostRunStart();
return true;
}
void DestroyTest(const RequestRunSettings& settings) override {
base::WaitableEvent event(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
// Browser process test is complete.
void OnRunnerRunComplete() override {
PostRunStart();
}
void PostRunStart() {
CefPostTask(TID_FILE,
base::Bind(&RequestTestHandler::PostRunFileTasks, this));
}
void PostRunFileTasks() {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
// Don't use WaitableEvent on the UI thread.
bool has_save_cookie = false;
GetTestCookie(test_runner_->GetRequestContext(), &event, &has_save_cookie);
EXPECT_EQ(settings.expect_save_cookie, has_save_cookie);
GetTestCookie(test_runner_->GetRequestContext(), &has_save_cookie);
EXPECT_EQ(test_runner_->settings_.expect_save_cookie, has_save_cookie);
CefPostTask(TID_UI, base::Bind(&RequestTestHandler::PostRunComplete, this));
}
void PostRunComplete() {
EXPECT_TRUE(CefCurrentlyOn(TID_UI));
DestroyTest();
}
void DestroyTest() override {
TestHandler::DestroyTest();
// Need to call TestComplete() explicitly if testing in the browser and
@ -1116,10 +1324,37 @@ class RequestTestHandler : public TestHandler,
// Release our reference to the context. Do not access any object members
// after this call because |this| might be deleted.
test_runner_->SetRequestContext(NULL);
test_runner_->Destroy();
if (call_test_complete)
OnTestComplete();
}
void OnTestComplete() {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI,
base::Bind(&RequestTestHandler::OnTestComplete, this));
return;
}
if (!context_tmpdir_.IsEmpty()) {
// Wait a bit for cache file handles to close after browser or request
// context destruction.
CefPostDelayedTask(TID_FILE,
base::Bind(&RequestTestHandler::PostTestCompleteFileTasks, this),
100);
} else {
TestComplete();
}
}
void PostTestCompleteFileTasks() {
EXPECT_TRUE(CefCurrentlyOn(TID_FILE));
EXPECT_TRUE(context_tmpdir_.Delete());
EXPECT_TRUE(context_tmpdir_.IsEmpty());
CefPostTask(TID_UI, base::Bind(&RequestTestHandler::TestComplete, this));
}
private:
@ -1131,7 +1366,7 @@ class RequestTestHandler : public TestHandler,
: test_handler_(test_handler) {
}
~RequestContextHandler() override {
test_handler_->TestComplete();
test_handler_->OnTestComplete();
}
private:
@ -1144,15 +1379,18 @@ class RequestTestHandler : public TestHandler,
class SupportedSchemesCompletionCallback : public CefCompletionCallback {
public:
explicit SupportedSchemesCompletionCallback(
CefRefPtr<RequestTestHandler> test_handler)
: test_handler_(test_handler) {
const base::Closure& complete_callback)
: complete_callback_(complete_callback) {
EXPECT_FALSE(complete_callback_.is_null());
}
void OnComplete() override {
test_handler_->RunTestContinue();
complete_callback_.Run();
complete_callback_.Reset();
}
private:
CefRefPtr<RequestTestHandler> test_handler_;
base::Closure complete_callback_;
IMPLEMENT_REFCOUNTING(SupportedSchemesCompletionCallback);
};
@ -1164,7 +1402,8 @@ class RequestTestHandler : public TestHandler,
scoped_refptr<RequestTestRunner> test_runner_;
base::ScopedTempDir context_tmpdir_;
CefScopedTempDir context_tmpdir_;
CefString context_tmpdir_path_;
public:
// Only used when the test runs in the render process.