- add sources.
[platform/framework/web/crosswalk.git] / src / chrome_frame / test / dll_redirector_loading_test.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // A test that exercises Chrome Frame's DLL Redirctor update code. This test
6 // generates a new version of CF from the one already in the build folder and
7 // then loads them both into the current process to verify the handoff.
8
9 #include "base/file_util.h"
10 #include "base/file_version_info.h"
11 #include "base/files/file_path.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/memory/shared_memory.h"
14 #include "base/path_service.h"
15 #include "base/scoped_native_library.h"
16 #include "base/strings/string_util.h"
17 #include "base/version.h"
18 #include "base/win/scoped_comptr.h"
19 #include "chrome/installer/test/alternate_version_generator.h"
20 #include "chrome/installer/util/delete_after_reboot_helper.h"
21 #include "chrome_frame/chrome_tab.h"
22 #include "chrome_frame/test_utils.h"
23 #include "chrome_frame/utils.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace {
27 const wchar_t kSharedMemoryPrefix[] = L"ChromeFrameVersionBeacon_";
28 const uint32 kSharedMemoryBytes = 128;
29 }
30
31 class DllRedirectorLoadingTest : public testing::Test {
32  public:
33   // This sets up the following directory structure:
34   //  TEMP\<version X>\npchrome_frame.dll
35   //      \<version X+1>\npchrome_frame.dll
36   //
37   // This structure emulates enough of the directory structure of a Chrome
38   // install to test upgrades.
39   static void SetUpTestCase() {
40     // First ensure that we can find the built Chrome Frame DLL.
41     base::FilePath build_chrome_frame_dll = GetChromeFrameBuildPath();
42     ASSERT_TRUE(base::PathExists(build_chrome_frame_dll));
43
44     // Then grab its version.
45     scoped_ptr<FileVersionInfo> original_version_info(
46         FileVersionInfo::CreateFileVersionInfo(build_chrome_frame_dll));
47     ASSERT_TRUE(original_version_info != NULL);
48     original_version_.reset(
49         new Version(WideToASCII(original_version_info->file_version())));
50     ASSERT_TRUE(original_version_->IsValid());
51
52     // Make a place for us to run the test from.
53     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
54
55     // Make a versioned dir for the original chrome frame dll to run under.
56     base::FilePath original_version_dir(
57         temp_dir_.path().AppendASCII(original_version_->GetString()));
58     ASSERT_TRUE(file_util::CreateDirectory(original_version_dir));
59
60     // Now move the original DLL that we will operate on into a named-version
61     // folder.
62     original_chrome_frame_dll_ =
63         original_version_dir.Append(build_chrome_frame_dll.BaseName());
64     ASSERT_TRUE(base::CopyFile(build_chrome_frame_dll,
65                                original_chrome_frame_dll_));
66     ASSERT_TRUE(base::PathExists(original_chrome_frame_dll_));
67
68     // Temporary location for the new Chrome Frame DLL.
69     base::FilePath temporary_new_chrome_frame_dll(
70         temp_dir_.path().Append(build_chrome_frame_dll.BaseName()));
71
72     // Generate the version-bumped Chrome Frame DLL to a temporary path.
73     ASSERT_TRUE(
74         upgrade_test::GenerateAlternatePEFileVersion(
75             original_chrome_frame_dll_,
76             temporary_new_chrome_frame_dll,
77             upgrade_test::NEXT_VERSION));
78
79     // Ensure it got created and grab its version.
80     scoped_ptr<FileVersionInfo> new_version_info(
81         FileVersionInfo::CreateFileVersionInfo(temporary_new_chrome_frame_dll));
82     ASSERT_TRUE(new_version_info != NULL);
83     new_version_.reset(
84         new Version(WideToASCII(new_version_info->file_version())));
85     ASSERT_TRUE(new_version_->IsValid());
86
87     // Make sure the new version is larger than the old.
88     ASSERT_EQ(new_version_->CompareTo(*original_version_.get()), 1);
89
90     // Now move the new Chrome Frame dll to its final resting place:
91     base::FilePath new_version_dir(
92         temp_dir_.path().AppendASCII(new_version_->GetString()));
93     ASSERT_TRUE(file_util::CreateDirectory(new_version_dir));
94     new_chrome_frame_dll_ =
95         new_version_dir.Append(build_chrome_frame_dll.BaseName());
96     ASSERT_TRUE(base::Move(temporary_new_chrome_frame_dll,
97                            new_chrome_frame_dll_));
98     ASSERT_TRUE(base::PathExists(new_chrome_frame_dll_));
99   }
100
101   static void TearDownTestCase() {
102     if (!temp_dir_.Delete()) {
103       // The temp_dir cleanup has been observed to fail in some cases. It looks
104       // like something is holding on to the Chrome Frame DLLs after they have
105       // been explicitly unloaded. At least schedule them for cleanup on reboot.
106       ScheduleDirectoryForDeletion(temp_dir_.path());
107     }
108   }
109
110  protected:
111   static base::FilePath original_chrome_frame_dll_;
112   static base::FilePath new_chrome_frame_dll_;
113   static scoped_ptr<Version> original_version_;
114   static scoped_ptr<Version> new_version_;
115
116   static base::ScopedTempDir temp_dir_;
117 };  // class DllRedirectorLoadingTest
118
119 base::FilePath DllRedirectorLoadingTest::original_chrome_frame_dll_;
120 base::FilePath DllRedirectorLoadingTest::new_chrome_frame_dll_;
121 scoped_ptr<Version> DllRedirectorLoadingTest::original_version_;
122 scoped_ptr<Version> DllRedirectorLoadingTest::new_version_;
123 base::ScopedTempDir DllRedirectorLoadingTest::temp_dir_;
124
125 #if defined(COMPONENT_BUILD)
126 // Disabling since npchrome_frame.dll's DllMain can't handle being loaded into
127 // a process that has already started services in base.dll such as logging; see
128 // http://crbug.com/110492.
129 #define MAYBE_TestDllRedirection DISABLED_TestDllRedirection
130 #else
131 #define MAYBE_TestDllRedirection TestDllRedirection
132 #endif
133
134 TEST_F(DllRedirectorLoadingTest, MAYBE_TestDllRedirection) {
135   struct TestData {
136     base::FilePath first_dll;
137     base::FilePath second_dll;
138     Version* expected_beacon_version;
139   } test_data[] = {
140       {
141           original_chrome_frame_dll_,
142           new_chrome_frame_dll_,
143           original_version_.get()
144       },
145       {
146           new_chrome_frame_dll_,
147           original_chrome_frame_dll_,
148           new_version_.get()
149       }
150   };
151
152   for (int i = 0; i < arraysize(test_data); ++i) {
153     // First load the original dll into our test process.
154     base::ScopedNativeLibrary original_library(test_data[i].first_dll);
155
156     ASSERT_TRUE(original_library.is_valid());
157
158     // Now query the original dll for its DllGetClassObject method and use that
159     // to get the class factory for a known CLSID.
160     LPFNGETCLASSOBJECT original_dgco_ptr =
161         reinterpret_cast<LPFNGETCLASSOBJECT>(
162             original_library.GetFunctionPointer("DllGetClassObject"));
163
164     ASSERT_TRUE(original_dgco_ptr != NULL);
165
166     base::win::ScopedComPtr<IClassFactory> original_class_factory;
167     HRESULT hr = original_dgco_ptr(
168         CLSID_ChromeFrame,
169         IID_IClassFactory,
170         reinterpret_cast<void**>(original_class_factory.Receive()));
171
172     ASSERT_HRESULT_SUCCEEDED(hr);
173
174     // Now load the new dll into our test process.
175     base::ScopedNativeLibrary new_library(test_data[i].second_dll);
176
177     ASSERT_TRUE(new_library.is_valid());
178
179     // Now query the new dll for its DllGetClassObject method and use that
180     // to get the class factory for a known CLSID.
181     LPFNGETCLASSOBJECT new_dgco_ptr =
182         reinterpret_cast<LPFNGETCLASSOBJECT>(
183             new_library.GetFunctionPointer("DllGetClassObject"));
184
185     ASSERT_TRUE(new_dgco_ptr != NULL);
186
187     base::win::ScopedComPtr<IClassFactory> new_class_factory;
188     hr = new_dgco_ptr(CLSID_ChromeFrame,
189                       IID_IClassFactory,
190                       reinterpret_cast<void**>(new_class_factory.Receive()));
191
192     ASSERT_HRESULT_SUCCEEDED(hr);
193
194     base::win::ScopedComPtr<IUnknown> qi_test;
195     EXPECT_HRESULT_SUCCEEDED(original_class_factory.QueryInterface(IID_IUnknown,
196           reinterpret_cast<void**>(qi_test.Receive())));
197
198     EXPECT_TRUE(new_class_factory.IsSameObject(qi_test));
199
200     // Check the version beacon.
201     std::wstring beacon_name(kSharedMemoryPrefix);
202     beacon_name += GetHostProcessName(false /* without extension */);
203     base::SharedMemory beacon(beacon_name);
204
205     EXPECT_TRUE(beacon.Open(WideToASCII(beacon_name), true /* read_only */));
206     EXPECT_TRUE(beacon.Map(0));
207     EXPECT_TRUE(beacon.memory());
208
209     char buffer[kSharedMemoryBytes] = {0};
210     memcpy(buffer, beacon.memory(), kSharedMemoryBytes - 1);
211     Version beacon_version(buffer);
212     ASSERT_TRUE(beacon_version.IsValid());
213
214     EXPECT_EQ(0,
215               beacon_version.CompareTo(*test_data[i].expected_beacon_version));
216   }
217 }