| // 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. |
| |
| #include "chrome/browser/nacl_host/nacl_file_host.h" |
| |
| #include "base/basictypes.h" |
| #include "base/files/file_path.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/run_loop.h" |
| #include "base/test/scoped_path_override.h" |
| #include "base/threading/sequenced_worker_pool.h" |
| #include "chrome/browser/nacl_host/nacl_browser.h" |
| #include "components/nacl/common/nacl_browser_delegate.h" |
| #include "components/nacl/common/pnacl_types.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using nacl_file_host::PnaclCanOpenFile; |
| using nacl_file_host::EnsurePnaclInstalled; |
| |
| class TestNaClBrowserDelegate : public NaClBrowserDelegate { |
| public: |
| |
| TestNaClBrowserDelegate() : should_pnacl_install_succeed_(false) { } |
| |
| virtual void ShowNaClInfobar(int render_process_id, |
| int render_view_id, |
| int error_id) OVERRIDE { |
| } |
| |
| virtual bool DialogsAreSuppressed() OVERRIDE { |
| return false; |
| } |
| |
| virtual bool GetCacheDirectory(base::FilePath* cache_dir) OVERRIDE { |
| return false; |
| } |
| |
| virtual bool GetPluginDirectory(base::FilePath* plugin_dir) OVERRIDE { |
| return false; |
| } |
| |
| virtual bool GetPnaclDirectory(base::FilePath* pnacl_dir) OVERRIDE { |
| *pnacl_dir = pnacl_path_; |
| return true; |
| } |
| |
| virtual bool GetUserDirectory(base::FilePath* user_dir) OVERRIDE { |
| return false; |
| } |
| |
| virtual std::string GetVersionString() const OVERRIDE { |
| return std::string(); |
| } |
| |
| virtual ppapi::host::HostFactory* CreatePpapiHostFactory( |
| content::BrowserPpapiHost* ppapi_host) OVERRIDE { |
| return NULL; |
| } |
| |
| virtual bool MapUrlToLocalFilePath(const GURL& file_url, |
| bool use_blocking_api, |
| base::FilePath* file_path) OVERRIDE { |
| return false; |
| } |
| |
| virtual void SetDebugPatterns(std::string debug_patterns) OVERRIDE { |
| } |
| |
| virtual bool URLMatchesDebugPatterns(const GURL& manifest_url) OVERRIDE { |
| return false; |
| } |
| |
| virtual void TryInstallPnacl( |
| const base::Callback<void(bool)>& installed) OVERRIDE { |
| installed.Run(should_pnacl_install_succeed_); |
| } |
| |
| void SetPnaclDirectory(const base::FilePath& pnacl_dir) { |
| pnacl_path_ = pnacl_dir; |
| } |
| |
| // Indicate if we should mock the PNaCl install as succeeding |
| // or failing for the next test. |
| void SetShouldPnaclInstallSucceed(bool succeed) { |
| should_pnacl_install_succeed_ = succeed; |
| } |
| |
| private: |
| base::FilePath pnacl_path_; |
| bool should_pnacl_install_succeed_; |
| }; |
| |
| class NaClFileHostTest : public testing::Test { |
| protected: |
| NaClFileHostTest(); |
| virtual ~NaClFileHostTest(); |
| |
| virtual void SetUp() OVERRIDE { |
| nacl_browser_delegate_ = new TestNaClBrowserDelegate; |
| NaClBrowser::SetDelegate(nacl_browser_delegate_); |
| } |
| |
| virtual void TearDown() OVERRIDE { |
| NaClBrowser::SetDelegate(NULL); // This deletes nacl_browser_delegate_ |
| } |
| |
| TestNaClBrowserDelegate* nacl_browser_delegate() { |
| return nacl_browser_delegate_; |
| } |
| |
| bool install_success() { return install_success_; } |
| size_t install_call_count() { |
| return std::count(events_.begin(), events_.end(), INSTALL_DONE); |
| } |
| size_t progress_call_count() { |
| return std::count(events_.begin(), events_.end(), INSTALL_PROGRESS); |
| } |
| bool events_in_correct_order() { |
| // INSTALL_DONE should be the last thing. |
| // The rest should be progress events. |
| size_t size = events_.size(); |
| return size > 0 && events_[size - 1] == INSTALL_DONE |
| && progress_call_count() == (size - 1); |
| } |
| |
| public: // Allow classes to bind these callback methods. |
| void CallbackInstall(bool success) { |
| install_success_ = success; |
| events_.push_back(INSTALL_DONE); |
| } |
| |
| void CallbackProgress(const nacl::PnaclInstallProgress& p) { |
| // Check that the first event has an unknown total. |
| if (events_.size() == 0) { |
| EXPECT_FALSE(nacl::PnaclInstallProgress::progress_known(p)); |
| } |
| events_.push_back(INSTALL_PROGRESS); |
| // TODO(jvoung): be able to check that current_progress |
| // goes up monotonically and hits total_progress at the end, |
| // when we actually get real progress events. |
| } |
| |
| private: |
| enum EventType { |
| INSTALL_DONE, |
| INSTALL_PROGRESS |
| }; |
| TestNaClBrowserDelegate* nacl_browser_delegate_; |
| bool install_success_; |
| std::vector<EventType> events_; |
| content::TestBrowserThreadBundle thread_bundle_; |
| DISALLOW_COPY_AND_ASSIGN(NaClFileHostTest); |
| }; |
| |
| NaClFileHostTest::NaClFileHostTest() |
| : nacl_browser_delegate_(NULL), |
| install_success_(false), |
| thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { |
| } |
| |
| NaClFileHostTest::~NaClFileHostTest() { |
| } |
| |
| // Try to pass a few funny filenames with a dummy PNaCl directory set. |
| TEST_F(NaClFileHostTest, TestFilenamesWithPnaclPath) { |
| base::ScopedTempDir scoped_tmp_dir; |
| ASSERT_TRUE(scoped_tmp_dir.CreateUniqueTempDir()); |
| |
| base::FilePath kTestPnaclPath = scoped_tmp_dir.path(); |
| |
| nacl_browser_delegate()->SetPnaclDirectory(kTestPnaclPath); |
| ASSERT_TRUE(NaClBrowser::GetDelegate()->GetPnaclDirectory(&kTestPnaclPath)); |
| |
| // Check allowed strings, and check that the expected prefix is added. |
| base::FilePath out_path; |
| EXPECT_TRUE(PnaclCanOpenFile("pnacl_json", &out_path)); |
| base::FilePath expected_path = kTestPnaclPath.Append( |
| FILE_PATH_LITERAL("pnacl_public_pnacl_json")); |
| EXPECT_EQ(expected_path, out_path); |
| |
| EXPECT_TRUE(PnaclCanOpenFile("x86_32_llc", &out_path)); |
| expected_path = kTestPnaclPath.Append( |
| FILE_PATH_LITERAL("pnacl_public_x86_32_llc")); |
| EXPECT_EQ(expected_path, out_path); |
| |
| // Check character ranges. |
| EXPECT_FALSE(PnaclCanOpenFile(".xchars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("/xchars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("x/chars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("\\xchars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("x\\chars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("$xchars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("%xchars", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("CAPS", &out_path)); |
| const char non_ascii[] = "\xff\xfe"; |
| EXPECT_FALSE(PnaclCanOpenFile(non_ascii, &out_path)); |
| |
| // Check file length restriction. |
| EXPECT_FALSE(PnaclCanOpenFile("thisstringisactuallywaaaaaaaaaaaaaaaaaaaaaaaa" |
| "toolongwaytoolongwaaaaayyyyytoooooooooooooooo" |
| "looooooooong", |
| &out_path)); |
| |
| // Other bad files. |
| EXPECT_FALSE(PnaclCanOpenFile(std::string(), &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile(".", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("..", &out_path)); |
| #if defined(OS_WIN) |
| EXPECT_FALSE(PnaclCanOpenFile("..\\llc", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("%SystemRoot%", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("%SystemRoot%\\explorer.exe", &out_path)); |
| #else |
| EXPECT_FALSE(PnaclCanOpenFile("../llc", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("/bin/sh", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("$HOME", &out_path)); |
| EXPECT_FALSE(PnaclCanOpenFile("$HOME/.bashrc", &out_path)); |
| #endif |
| } |
| |
| // Test that callbacks return success when PNaCl looks like it is |
| // already installed. No intermediate progress events are expected. |
| TEST_F(NaClFileHostTest, TestEnsureInstalledAlreadyInstalled) { |
| base::ScopedTempDir scoped_tmp_dir; |
| ASSERT_TRUE(scoped_tmp_dir.CreateUniqueTempDir()); |
| |
| base::FilePath kTestPnaclPath = scoped_tmp_dir.path(); |
| nacl_browser_delegate()->SetPnaclDirectory(kTestPnaclPath); |
| ASSERT_TRUE(NaClBrowser::GetDelegate()->GetPnaclDirectory(&kTestPnaclPath)); |
| |
| EnsurePnaclInstalled( |
| base::Bind(&NaClFileHostTest::CallbackInstall, base::Unretained(this)), |
| base::Bind(&NaClFileHostTest::CallbackProgress, base::Unretained(this))); |
| content::BrowserThread::GetBlockingPool()->FlushForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(install_success()); |
| EXPECT_EQ(1u, install_call_count()); |
| EXPECT_EQ(0u, progress_call_count()); |
| EXPECT_TRUE(events_in_correct_order()); |
| } |
| |
| // Test that final callback is called with success, when PNaCl does not |
| // look like it's already installed, but mock installer says success. |
| // Also check that intermediate progress events are called. |
| TEST_F(NaClFileHostTest, TestEnsureInstalledNotInstalledSuccess) { |
| base::FilePath kTestPnaclPath; |
| nacl_browser_delegate()->SetPnaclDirectory(kTestPnaclPath); |
| nacl_browser_delegate()->SetShouldPnaclInstallSucceed(true); |
| |
| EnsurePnaclInstalled( |
| base::Bind(&NaClFileHostTest::CallbackInstall, base::Unretained(this)), |
| base::Bind(&NaClFileHostTest::CallbackProgress, base::Unretained(this))); |
| content::BrowserThread::GetBlockingPool()->FlushForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(install_success()); |
| EXPECT_EQ(1u, install_call_count()); |
| EXPECT_GE(progress_call_count(), 1u); |
| EXPECT_TRUE(events_in_correct_order()); |
| } |
| |
| // Test that final callback is called with error, when PNaCl does not look |
| // like it's already installed, but mock installer says error. |
| // Also check that intermediate progress events are called. |
| TEST_F(NaClFileHostTest, TestEnsureInstalledNotInstalledError) { |
| base::FilePath kTestPnaclPath; |
| nacl_browser_delegate()->SetPnaclDirectory(kTestPnaclPath); |
| nacl_browser_delegate()->SetShouldPnaclInstallSucceed(false); |
| |
| EnsurePnaclInstalled( |
| base::Bind(&NaClFileHostTest::CallbackInstall, base::Unretained(this)), |
| base::Bind(&NaClFileHostTest::CallbackProgress, base::Unretained(this))); |
| content::BrowserThread::GetBlockingPool()->FlushForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(install_success()); |
| EXPECT_EQ(1u, install_call_count()); |
| EXPECT_GE(progress_call_count(), 1u); |
| EXPECT_TRUE(events_in_correct_order()); |
| } |