1 // Copyright 2019 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 "components/services/storage/storage_service_impl.h"
6 
7 #include "base/files/file_path.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/macros.h"
10 #include "base/run_loop.h"
11 #include "base/test/task_environment.h"
12 #include "components/services/storage/partition_impl.h"
13 #include "components/services/storage/public/mojom/partition.mojom.h"
14 #include "components/services/storage/public/mojom/storage_service.mojom.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 
17 namespace storage {
18 
19 class StorageServiceImplTest : public testing::Test {
20  public:
21   StorageServiceImplTest() = default;
22   ~StorageServiceImplTest() override = default;
23 
24  protected:
remote_service()25   mojom::StorageService* remote_service() { return remote_service_.get(); }
service_impl()26   StorageServiceImpl& service_impl() { return service_; }
27 
28  private:
29   base::test::TaskEnvironment task_environment_;
30   mojo::Remote<mojom::StorageService> remote_service_;
31   StorageServiceImpl service_{remote_service_.BindNewPipeAndPassReceiver(),
32                               /*io_task_runner=*/nullptr};
33 
34   DISALLOW_COPY_AND_ASSIGN(StorageServiceImplTest);
35 };
36 
TEST_F(StorageServiceImplTest,UniqueInMemoryPartitions)37 TEST_F(StorageServiceImplTest, UniqueInMemoryPartitions) {
38   // Verifies that every partition client bound without a path is bound to a
39   // unique partition instance.
40 
41   mojo::Remote<mojom::Partition> in_memory_partition1;
42   remote_service()->BindPartition(
43       /*path=*/base::nullopt,
44       in_memory_partition1.BindNewPipeAndPassReceiver());
45   in_memory_partition1.FlushForTesting();
46 
47   EXPECT_EQ(1u, service_impl().partitions().size());
48 
49   mojo::Remote<mojom::Partition> in_memory_partition2;
50   remote_service()->BindPartition(
51       base::nullopt /* path */,
52       in_memory_partition2.BindNewPipeAndPassReceiver());
53   in_memory_partition2.FlushForTesting();
54 
55   EXPECT_EQ(2u, service_impl().partitions().size());
56 
57   // Also verify that a new client with a provided path is unique from the above
58   // partitions.
59   base::ScopedTempDir temp_dir;
60   CHECK(temp_dir.CreateUniqueTempDir());
61 
62   mojo::Remote<mojom::Partition> persistent_partition;
63   remote_service()->BindPartition(
64       temp_dir.GetPath(), persistent_partition.BindNewPipeAndPassReceiver());
65   persistent_partition.FlushForTesting();
66 
67   EXPECT_EQ(3u, service_impl().partitions().size());
68 }
69 
TEST_F(StorageServiceImplTest,SharedPersistentPartition)70 TEST_F(StorageServiceImplTest, SharedPersistentPartition) {
71   // Verifies that multiple clients can share the same persistent partition
72   // instance.
73 
74   base::ScopedTempDir temp_dir;
75   CHECK(temp_dir.CreateUniqueTempDir());
76 
77   mojo::Remote<mojom::Partition> client1;
78   remote_service()->BindPartition(temp_dir.GetPath(),
79                                   client1.BindNewPipeAndPassReceiver());
80   client1.FlushForTesting();
81 
82   EXPECT_EQ(1u, service_impl().partitions().size());
83 
84   mojo::Remote<mojom::Partition> client2;
85   remote_service()->BindPartition(temp_dir.GetPath(),
86                                   client2.BindNewPipeAndPassReceiver());
87   client2.FlushForTesting();
88 
89   EXPECT_EQ(1u, service_impl().partitions().size());
90   EXPECT_TRUE(client1.is_connected());
91   EXPECT_TRUE(client2.is_connected());
92 }
93 
TEST_F(StorageServiceImplTest,PartitionDestroyedOnLastClientDisconnect)94 TEST_F(StorageServiceImplTest, PartitionDestroyedOnLastClientDisconnect) {
95   base::ScopedTempDir temp_dir;
96   CHECK(temp_dir.CreateUniqueTempDir());
97 
98   mojo::Remote<mojom::Partition> client1;
99   remote_service()->BindPartition(temp_dir.GetPath(),
100                                   client1.BindNewPipeAndPassReceiver());
101   client1.FlushForTesting();
102 
103   mojo::Remote<mojom::Partition> client2;
104   remote_service()->BindPartition(temp_dir.GetPath(),
105                                   client2.BindNewPipeAndPassReceiver());
106   client2.FlushForTesting();
107 
108   EXPECT_EQ(1u, service_impl().partitions().size());
109 
110   client1.reset();
111   client2.reset();
112 
113   base::RunLoop().RunUntilIdle();
114 
115   EXPECT_EQ(0u, service_impl().partitions().size());
116 }
117 
TEST_F(StorageServiceImplTest,PersistentPartitionRequiresAbsolutePath)118 TEST_F(StorageServiceImplTest, PersistentPartitionRequiresAbsolutePath) {
119   mojo::Remote<mojom::Partition> client;
120   const base::FilePath kTestRelativePath{FILE_PATH_LITERAL("invalid")};
121   remote_service()->BindPartition(kTestRelativePath,
122                                   client.BindNewPipeAndPassReceiver());
123 
124   // We should be imminently disconnected because the BindPartition request
125   // should be ignored by the service.
126   base::RunLoop loop;
127   client.set_disconnect_handler(loop.QuitClosure());
128   loop.Run();
129 
130   EXPECT_FALSE(client.is_connected());
131 }
132 
133 }  // namespace storage
134