- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / fileapi / fileapi_message_filter_unittest.cc
1 // Copyright 2013 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 #include "content/browser/fileapi/fileapi_message_filter.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/shared_memory.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/process/process.h"
14 #include "content/browser/child_process_security_policy_impl.h"
15 #include "content/browser/fileapi/chrome_blob_storage_context.h"
16 #include "content/browser/streams/stream_registry.h"
17 #include "content/common/fileapi/file_system_messages.h"
18 #include "content/common/fileapi/webblob_messages.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/common/common_param_traits.h"
21 #include "content/public/test/mock_render_process_host.h"
22 #include "content/public/test/test_browser_context.h"
23 #include "content/public/test/test_browser_thread.h"
24 #include "content/public/test/test_file_system_context.h"
25 #include "net/base/io_buffer.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "webkit/browser/blob/blob_storage_context.h"
28 #include "webkit/browser/fileapi/file_system_context.h"
29 #include "webkit/common/blob/blob_data.h"
30
31 namespace content {
32
33 namespace {
34
35 const char kFakeBlobInternalUrlSpec[] =
36     "blob:blobinternal%3A///dc83ede4-9bbd-453b-be2e-60fd623fcc93";
37 const char kFakeBlobInternalUrlSpec2[] =
38     "blob:blobinternal%3A///d28ae2e7-d233-4dda-9598-d135fe5d403e";
39
40 const char kFakeContentType[] = "fake/type";
41
42 }  // namespace
43
44 class FileAPIMessageFilterTest : public testing::Test {
45  public:
46   FileAPIMessageFilterTest()
47       : io_browser_thread_(BrowserThread::IO, &message_loop_) {
48   }
49
50  protected:
51   virtual void SetUp() OVERRIDE {
52     file_system_context_ =
53         fileapi::CreateFileSystemContextForTesting(NULL, base::FilePath());
54
55     std::vector<fileapi::FileSystemType> types;
56     file_system_context_->GetFileSystemTypes(&types);
57     for (size_t i = 0; i < types.size(); ++i) {
58       ChildProcessSecurityPolicyImpl::GetInstance()->
59           RegisterFileSystemPermissionPolicy(
60               types[i],
61               fileapi::FileSystemContext::GetPermissionPolicy(types[i]));
62     }
63
64     stream_context_ = StreamContext::GetFor(&browser_context_);
65     blob_storage_context_ = ChromeBlobStorageContext::GetFor(&browser_context_);
66
67     filter_ = new FileAPIMessageFilter(
68         0 /* process_id */,
69         browser_context_.GetRequestContext(),
70         file_system_context_.get(),
71         blob_storage_context_,
72         stream_context_);
73
74     // Complete initialization.
75     message_loop_.RunUntilIdle();
76   }
77
78   // Tests via OnMessageReceived(const IPC::Message&). The channel proxy calls
79   // this method.
80   bool InvokeOnMessageReceived(const IPC::Message& message) {
81     bool message_was_ok;
82     return filter_->OnMessageReceived(message, &message_was_ok);
83   }
84
85   base::MessageLoop message_loop_;
86   TestBrowserThread io_browser_thread_;
87
88   TestBrowserContext browser_context_;
89   scoped_refptr<fileapi::FileSystemContext> file_system_context_;
90   StreamContext* stream_context_;
91   ChromeBlobStorageContext* blob_storage_context_;
92
93   scoped_refptr<FileAPIMessageFilter> filter_;
94 };
95
96 TEST_F(FileAPIMessageFilterTest, CloseChannelWithInflightRequest) {
97   scoped_refptr<FileAPIMessageFilter> filter(
98       new FileAPIMessageFilter(
99           0 /* process_id */,
100           browser_context_.GetRequestContext(),
101           file_system_context_.get(),
102           ChromeBlobStorageContext::GetFor(&browser_context_),
103           StreamContext::GetFor(&browser_context_)));
104   filter->OnChannelConnected(0);
105
106   // Complete initialization.
107   message_loop_.RunUntilIdle();
108
109   int request_id = 0;
110   const GURL kUrl("filesystem:http://example.com/temporary/foo");
111   FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
112   bool message_was_ok;
113   EXPECT_TRUE(filter->OnMessageReceived(read_metadata, &message_was_ok));
114
115   // Close the filter while it has inflight request.
116   filter->OnChannelClosing();
117
118   // This shouldn't cause DCHECK failure.
119   message_loop_.RunUntilIdle();
120 }
121
122 TEST_F(FileAPIMessageFilterTest, MultipleFilters) {
123   scoped_refptr<FileAPIMessageFilter> filter1(
124       new FileAPIMessageFilter(
125           0 /* process_id */,
126           browser_context_.GetRequestContext(),
127           file_system_context_.get(),
128           ChromeBlobStorageContext::GetFor(&browser_context_),
129           StreamContext::GetFor(&browser_context_)));
130   scoped_refptr<FileAPIMessageFilter> filter2(
131       new FileAPIMessageFilter(
132           1 /* process_id */,
133           browser_context_.GetRequestContext(),
134           file_system_context_.get(),
135           ChromeBlobStorageContext::GetFor(&browser_context_),
136           StreamContext::GetFor(&browser_context_)));
137   filter1->OnChannelConnected(0);
138   filter2->OnChannelConnected(1);
139
140   // Complete initialization.
141   message_loop_.RunUntilIdle();
142
143   int request_id = 0;
144   const GURL kUrl("filesystem:http://example.com/temporary/foo");
145   FileSystemHostMsg_ReadMetadata read_metadata(request_id++, kUrl);
146   bool message_was_ok;
147   EXPECT_TRUE(filter1->OnMessageReceived(read_metadata, &message_was_ok));
148
149   // Close the other filter before the request for filter1 is processed.
150   filter2->OnChannelClosing();
151
152   // This shouldn't cause DCHECK failure.
153   message_loop_.RunUntilIdle();
154 }
155
156 TEST_F(FileAPIMessageFilterTest, BuildEmptyStream) {
157   StreamRegistry* stream_registry = stream_context_->registry();
158
159   const GURL kUrl(kFakeBlobInternalUrlSpec);
160   const GURL kDifferentUrl("blob:barfoo");
161
162   EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
163
164   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
165   EXPECT_TRUE(InvokeOnMessageReceived(start_message));
166
167   const int kBufferSize = 10;
168   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kBufferSize));
169   int bytes_read = 0;
170
171   scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
172   // Stream becomes available for read right after registration.
173   ASSERT_FALSE(stream.get() == NULL);
174   EXPECT_EQ(Stream::STREAM_EMPTY,
175             stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
176   EXPECT_EQ(0, bytes_read);
177   stream = NULL;
178
179   StreamHostMsg_FinishBuilding finish_message(kUrl);
180   EXPECT_TRUE(InvokeOnMessageReceived(finish_message));
181
182   stream = stream_registry->GetStream(kUrl);
183   ASSERT_FALSE(stream.get() == NULL);
184   EXPECT_EQ(Stream::STREAM_EMPTY,
185             stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
186   EXPECT_EQ(0, bytes_read);
187
188   // Run loop to finish transfer.
189   message_loop_.RunUntilIdle();
190
191   EXPECT_EQ(Stream::STREAM_COMPLETE,
192             stream->ReadRawData(buffer.get(), kBufferSize, &bytes_read));
193   EXPECT_EQ(0, bytes_read);
194
195   // Nothing should be returned for a URL we didn't use.
196   EXPECT_TRUE(stream_registry->GetStream(kDifferentUrl).get() == NULL);
197 }
198
199 TEST_F(FileAPIMessageFilterTest, BuildNonEmptyStream) {
200   StreamRegistry* stream_registry = stream_context_->registry();
201
202   const GURL kUrl(kFakeBlobInternalUrlSpec);
203
204   EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
205
206   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
207   EXPECT_TRUE(InvokeOnMessageReceived(start_message));
208
209   webkit_blob::BlobData::Item item;
210   const std::string kFakeData = "foobarbaz";
211   item.SetToBytes(kFakeData.data(), kFakeData.size());
212   StreamHostMsg_AppendBlobDataItem append_message(kUrl, item);
213   EXPECT_TRUE(InvokeOnMessageReceived(append_message));
214
215   StreamHostMsg_FinishBuilding finish_message(kUrl);
216   EXPECT_TRUE(InvokeOnMessageReceived(finish_message));
217
218   // Run loop to finish transfer and commit finalize command.
219   message_loop_.RunUntilIdle();
220
221   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
222   int bytes_read = 0;
223
224   scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
225   ASSERT_FALSE(stream.get() == NULL);
226
227   EXPECT_EQ(Stream::STREAM_HAS_DATA,
228             stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
229   EXPECT_EQ(kFakeData.size(), static_cast<size_t>(bytes_read));
230   EXPECT_EQ(kFakeData, std::string(buffer->data(), bytes_read));
231
232   EXPECT_EQ(Stream::STREAM_COMPLETE,
233             stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
234   EXPECT_EQ(0, bytes_read);
235 }
236
237 TEST_F(FileAPIMessageFilterTest, BuildStreamWithSharedMemory) {
238   StreamRegistry* stream_registry = stream_context_->registry();
239
240   const GURL kUrl(kFakeBlobInternalUrlSpec);
241
242   EXPECT_EQ(NULL, stream_registry->GetStream(kUrl).get());
243
244   // For win, we need to set valid PID to the filter.
245   // OnAppendSharedMemoryToStream passes the peer process's handle to
246   // SharedMemory's constructor. If it's incorrect, DuplicateHandle won't work
247   // correctly.
248   filter_->set_peer_pid_for_testing(base::Process::Current().pid());
249
250   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
251   EXPECT_TRUE(InvokeOnMessageReceived(start_message));
252
253   const std::string kFakeData = "foobarbaz";
254
255   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
256   ASSERT_TRUE(shared_memory->CreateAndMapAnonymous(kFakeData.size()));
257   memcpy(shared_memory->memory(), kFakeData.data(), kFakeData.size());
258   StreamHostMsg_SyncAppendSharedMemory append_message(
259       kUrl, shared_memory->handle(), kFakeData.size());
260   EXPECT_TRUE(InvokeOnMessageReceived(append_message));
261
262   StreamHostMsg_FinishBuilding finish_message(kUrl);
263   EXPECT_TRUE(InvokeOnMessageReceived(finish_message));
264
265   // Run loop to finish transfer and commit finalize command.
266   message_loop_.RunUntilIdle();
267
268   scoped_refptr<net::IOBuffer> buffer(new net::IOBuffer(kFakeData.size()));
269   int bytes_read = 0;
270
271   scoped_refptr<Stream> stream = stream_registry->GetStream(kUrl);
272   ASSERT_FALSE(stream.get() == NULL);
273
274   EXPECT_EQ(Stream::STREAM_HAS_DATA,
275             stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
276   EXPECT_EQ(kFakeData.size(), static_cast<size_t>(bytes_read));
277   EXPECT_EQ(kFakeData, std::string(buffer->data(), bytes_read));
278
279   EXPECT_EQ(Stream::STREAM_COMPLETE,
280             stream->ReadRawData(buffer.get(), kFakeData.size(), &bytes_read));
281   EXPECT_EQ(0, bytes_read);
282 }
283
284 TEST_F(FileAPIMessageFilterTest, BuildStreamAndCallOnChannelClosing) {
285   StreamRegistry* stream_registry = stream_context_->registry();
286
287   const GURL kUrl(kFakeBlobInternalUrlSpec);
288
289   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
290   EXPECT_TRUE(InvokeOnMessageReceived(start_message));
291
292   ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
293
294   filter_->OnChannelClosing();
295
296   ASSERT_EQ(NULL, stream_registry->GetStream(kUrl).get());
297 }
298
299 TEST_F(FileAPIMessageFilterTest, CloneStream) {
300   StreamRegistry* stream_registry = stream_context_->registry();
301
302   const GURL kUrl(kFakeBlobInternalUrlSpec);
303   const GURL kDestUrl(kFakeBlobInternalUrlSpec2);
304
305   StreamHostMsg_StartBuilding start_message(kUrl, kFakeContentType);
306   EXPECT_TRUE(InvokeOnMessageReceived(start_message));
307
308   StreamHostMsg_Clone clone_message(kDestUrl, kUrl);
309   EXPECT_TRUE(InvokeOnMessageReceived(clone_message));
310
311   ASSERT_FALSE(stream_registry->GetStream(kUrl).get() == NULL);
312   ASSERT_FALSE(stream_registry->GetStream(kDestUrl).get() == NULL);
313 }
314
315 }  // namespace content