1 // Copyright 2014 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 <stdint.h>
6 
7 #include <memory>
8 #include <set>
9 
10 #include "base/bind.h"
11 #include "base/macros.h"
12 #include "base/stl_util.h"
13 #include "base/test/task_environment.h"
14 #include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "url/origin.h"
17 
18 namespace content {
19 
20 namespace {
21 
22 struct ReportOutstandingState {
23   int true_calls = 0;
24   int false_calls = 0;
25 
no_callscontent::__anone14aa3bc0111::ReportOutstandingState26   bool no_calls() { return true_calls == 0 && false_calls == 0; }
27 };
28 
ReportOutstandingBlobs(ReportOutstandingState * state,bool blobs_outstanding)29 void ReportOutstandingBlobs(ReportOutstandingState* state,
30                             bool blobs_outstanding) {
31   if (blobs_outstanding) {
32     ++state->true_calls;
33   } else {
34     ++state->false_calls;
35   }
36 }
37 
38 struct UnusedBlob {
39   int64_t database_id;
40   int64_t blob_number;
41 
operator <content::__anone14aa3bc0111::UnusedBlob42   bool operator<(const UnusedBlob& other) const {
43     if (database_id == other.database_id)
44       return blob_number < other.blob_number;
45     return database_id < other.database_id;
46   }
47 };
48 
ReportUnusedBlob(std::set<UnusedBlob> * unused_blob_records,int64_t database_id,int64_t blob_number)49 void ReportUnusedBlob(std::set<UnusedBlob>* unused_blob_records,
50                       int64_t database_id,
51                       int64_t blob_number) {
52   unused_blob_records->insert({database_id, blob_number});
53 }
54 
55 // Base class for our test fixtures.
56 class IndexedDBActiveBlobRegistryTest : public testing::Test {
57  public:
58   static const int64_t kDatabaseId0 = 7;
59   static const int64_t kDatabaseId1 = 12;
60   static const int64_t kBlobNumber0 = 77;
61   static const int64_t kBlobNumber1 = 14;
62 
IndexedDBActiveBlobRegistryTest()63   IndexedDBActiveBlobRegistryTest()
64       : registry_(std::make_unique<IndexedDBActiveBlobRegistry>(
65             base::BindRepeating(ReportOutstandingBlobs,
66                                 &report_outstanding_state_),
67             base::BindRepeating(&ReportUnusedBlob, &unused_blobs_))) {}
68 
RunUntilIdle()69   void RunUntilIdle() { task_environment_.RunUntilIdle(); }
registry() const70   IndexedDBActiveBlobRegistry* registry() const { return registry_.get(); }
71 
72  protected:
73   ReportOutstandingState report_outstanding_state_;
74   std::set<UnusedBlob> unused_blobs_;
75 
76  private:
77   base::test::TaskEnvironment task_environment_;
78 
79   std::unique_ptr<IndexedDBActiveBlobRegistry> registry_;
80 
81   DISALLOW_COPY_AND_ASSIGN(IndexedDBActiveBlobRegistryTest);
82 };
83 
TEST_F(IndexedDBActiveBlobRegistryTest,DeleteUnused)84 TEST_F(IndexedDBActiveBlobRegistryTest, DeleteUnused) {
85   EXPECT_TRUE(report_outstanding_state_.no_calls());
86   EXPECT_TRUE(unused_blobs_.empty());
87 
88   EXPECT_FALSE(registry()->MarkBlobInfoDeletedAndCheckIfReferenced(
89       kDatabaseId0, kBlobNumber0));
90   RunUntilIdle();
91 
92   EXPECT_TRUE(report_outstanding_state_.no_calls());
93   EXPECT_TRUE(unused_blobs_.empty());
94 }
95 
TEST_F(IndexedDBActiveBlobRegistryTest,SimpleUse)96 TEST_F(IndexedDBActiveBlobRegistryTest, SimpleUse) {
97   EXPECT_TRUE(report_outstanding_state_.no_calls());
98   EXPECT_TRUE(unused_blobs_.empty());
99 
100   auto add_ref =
101       registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobNumber0);
102   auto release =
103       registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobNumber0);
104   std::move(add_ref).Run();
105   RunUntilIdle();
106 
107   EXPECT_EQ(1, report_outstanding_state_.true_calls);
108   EXPECT_EQ(0, report_outstanding_state_.false_calls);
109   EXPECT_TRUE(unused_blobs_.empty());
110 
111   std::move(release).Run();
112   RunUntilIdle();
113 
114   EXPECT_EQ(1, report_outstanding_state_.true_calls);
115   EXPECT_EQ(1, report_outstanding_state_.false_calls);
116   EXPECT_TRUE(unused_blobs_.empty());
117 }
118 
TEST_F(IndexedDBActiveBlobRegistryTest,DeleteWhileInUse)119 TEST_F(IndexedDBActiveBlobRegistryTest, DeleteWhileInUse) {
120   EXPECT_TRUE(report_outstanding_state_.no_calls());
121   EXPECT_TRUE(unused_blobs_.empty());
122 
123   auto add_ref =
124       registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobNumber0);
125   auto release =
126       registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobNumber0);
127 
128   std::move(add_ref).Run();
129   RunUntilIdle();
130 
131   EXPECT_EQ(1, report_outstanding_state_.true_calls);
132   EXPECT_EQ(0, report_outstanding_state_.false_calls);
133   EXPECT_TRUE(unused_blobs_.empty());
134 
135   EXPECT_TRUE(registry()->MarkBlobInfoDeletedAndCheckIfReferenced(
136       kDatabaseId0, kBlobNumber0));
137   RunUntilIdle();
138 
139   EXPECT_EQ(1, report_outstanding_state_.true_calls);
140   EXPECT_EQ(0, report_outstanding_state_.false_calls);
141   EXPECT_TRUE(unused_blobs_.empty());
142 
143   std::move(release).Run();
144   RunUntilIdle();
145 
146   EXPECT_EQ(1, report_outstanding_state_.true_calls);
147   EXPECT_EQ(1, report_outstanding_state_.false_calls);
148   UnusedBlob unused_blob = {kDatabaseId0, kBlobNumber0};
149   EXPECT_EQ(1u, unused_blobs_.size());
150   EXPECT_TRUE(base::Contains(unused_blobs_, unused_blob));
151 }
152 
TEST_F(IndexedDBActiveBlobRegistryTest,MultipleBlobs)153 TEST_F(IndexedDBActiveBlobRegistryTest, MultipleBlobs) {
154   EXPECT_TRUE(report_outstanding_state_.no_calls());
155   EXPECT_TRUE(unused_blobs_.empty());
156 
157   auto add_ref_00 =
158       registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobNumber0);
159   auto release_00 =
160       registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobNumber0);
161   auto add_ref_01 =
162       registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobNumber1);
163   auto release_01 =
164       registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobNumber1);
165   auto add_ref_10 =
166       registry()->GetMarkBlobActiveCallback(kDatabaseId1, kBlobNumber0);
167   auto release_10 =
168       registry()->GetFinalReleaseCallback(kDatabaseId1, kBlobNumber0);
169   auto add_ref_11 =
170       registry()->GetMarkBlobActiveCallback(kDatabaseId1, kBlobNumber1);
171   auto release_11 =
172       registry()->GetFinalReleaseCallback(kDatabaseId1, kBlobNumber1);
173 
174   std::move(add_ref_00).Run();
175   std::move(add_ref_01).Run();
176   RunUntilIdle();
177 
178   EXPECT_EQ(1, report_outstanding_state_.true_calls);
179   EXPECT_EQ(0, report_outstanding_state_.false_calls);
180   EXPECT_TRUE(unused_blobs_.empty());
181 
182   std::move(release_00).Run();
183   std::move(add_ref_10).Run();
184   std::move(add_ref_11).Run();
185   RunUntilIdle();
186 
187   EXPECT_EQ(1, report_outstanding_state_.true_calls);
188   EXPECT_EQ(0, report_outstanding_state_.false_calls);
189   EXPECT_TRUE(unused_blobs_.empty());
190 
191   EXPECT_TRUE(registry()->MarkBlobInfoDeletedAndCheckIfReferenced(
192       kDatabaseId0, kBlobNumber1));
193   RunUntilIdle();
194 
195   EXPECT_EQ(1, report_outstanding_state_.true_calls);
196   EXPECT_EQ(0, report_outstanding_state_.false_calls);
197   EXPECT_TRUE(unused_blobs_.empty());
198 
199   std::move(release_01).Run();
200   std::move(release_11).Run();
201   RunUntilIdle();
202 
203   EXPECT_EQ(1, report_outstanding_state_.true_calls);
204   EXPECT_EQ(0, report_outstanding_state_.false_calls);
205   UnusedBlob unused_blob = {kDatabaseId0, kBlobNumber1};
206   EXPECT_TRUE(base::Contains(unused_blobs_, unused_blob));
207   EXPECT_EQ(1u, unused_blobs_.size());
208 
209   std::move(release_10).Run();
210   RunUntilIdle();
211 
212   EXPECT_EQ(1, report_outstanding_state_.true_calls);
213   EXPECT_EQ(1, report_outstanding_state_.false_calls);
214   unused_blob = {kDatabaseId0, kBlobNumber1};
215   EXPECT_TRUE(base::Contains(unused_blobs_, unused_blob));
216   EXPECT_EQ(1u, unused_blobs_.size());
217 }
218 
TEST_F(IndexedDBActiveBlobRegistryTest,ForceShutdown)219 TEST_F(IndexedDBActiveBlobRegistryTest, ForceShutdown) {
220   EXPECT_TRUE(report_outstanding_state_.no_calls());
221   EXPECT_TRUE(unused_blobs_.empty());
222 
223   auto add_ref_0 =
224       registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobNumber0);
225   auto release_0 =
226       registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobNumber0);
227   auto add_ref_1 =
228       registry()->GetMarkBlobActiveCallback(kDatabaseId0, kBlobNumber1);
229   auto release_1 =
230       registry()->GetFinalReleaseCallback(kDatabaseId0, kBlobNumber1);
231 
232   std::move(add_ref_0).Run();
233   RunUntilIdle();
234 
235   EXPECT_EQ(1, report_outstanding_state_.true_calls);
236   EXPECT_EQ(0, report_outstanding_state_.false_calls);
237   EXPECT_TRUE(unused_blobs_.empty());
238 
239   registry()->ForceShutdown();
240 
241   std::move(add_ref_1).Run();
242   RunUntilIdle();
243 
244   // Nothing changes.
245   EXPECT_EQ(1, report_outstanding_state_.true_calls);
246   EXPECT_EQ(0, report_outstanding_state_.false_calls);
247   EXPECT_TRUE(unused_blobs_.empty());
248 
249   std::move(release_0).Run();
250   std::move(release_1).Run();
251   RunUntilIdle();
252 
253   // Nothing changes.
254   EXPECT_EQ(1, report_outstanding_state_.true_calls);
255   EXPECT_EQ(0, report_outstanding_state_.false_calls);
256   EXPECT_TRUE(unused_blobs_.empty());
257 }
258 
259 }  // namespace
260 
261 }  // namespace content
262