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