Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /main /. /sql /streaming_blob_handle_unittest.cc
blob: ce0b7b4819f911b7a2232e6553b2fd7c5c3afb8a [file] [log] [blame]
Evan Stade416f46f12025-06-18 15:42:39[diff] [blame]1// Copyright 2025 The Chromium Authors
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"sql/streaming_blob_handle.h"
6
7#include<stddef.h>
8#include<stdint.h>
9
10#include<functional>
11#include<memory>
12#include<optional>
13#include<string>
14#include<utility>
15
16#include"base/containers/span.h"
17#include"base/files/scoped_temp_dir.h"
18#include"base/functional/bind.h"
19#include"base/test/bind.h"
20#include"base/time/time.h"
21#include"sql/database.h"
22#include"sql/sqlite_result_code.h"
23#include"sql/statement.h"
24#include"sql/statement_id.h"
25#include"sql/test/test_helpers.h"
26#include"sql/transaction.h"
27#include"testing/gtest/include/gtest/gtest.h"
28#include"third_party/sqlite/sqlite3.h"
29
30namespace sql{
31
32classStreamingBlobHandleTest:public testing::Test{
33public:
34voidSetUp() override{
35 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
36 ASSERT_TRUE(db_.Open(
37 temp_dir_.GetPath().AppendASCII("streaming_blob_test.sqlite")));
38}
39
40protected:
41 base::ScopedTempDir temp_dir_;
42Database db_{test::kTestTag};
43};
44
45TEST_F(StreamingBlobHandleTest,Basic){
46staticconstsize_t kBlobSize=128;
47
48 std::optional<Transaction> transaction;
49 transaction.emplace(&db_);
50 ASSERT_TRUE(transaction->Begin());
51
52staticconstexprchar kCreateSql[]=
53"CREATE TABLE foo (id INTEGER PRIMARY KEY AUTOINCREMENT, data BLOB, "
54"timestamp INTEGER NOT NULL)";
55 ASSERT_TRUE(db_.Execute(kCreateSql));
56
57// Insert a row with a blob that is yet to be written.
58{
59Statement statement(db_.GetCachedStatement(
60 SQL_FROM_HERE,"INSERT INTO foo (data, timestamp) VALUES (?, ?)"));
61 statement.BindBlobForStreaming(0, kBlobSize);
62 statement.BindTime(1, base::Time::Now());
63 ASSERT_TRUE(statement.Run());
64}
65
66constint64_t row_id= db_.GetLastInsertRowId();
67
68// Write the blob.
69 std::optional<StreamingBlobHandle> writing_blob=
70 db_.GetStreamingBlob("foo","data", row_id,/*readonly=*/false);
71 ASSERT_TRUE(writing_blob.has_value());
72
73staticconstint kChunkSize=8;
74for(size_t i=0; i< kBlobSize/ kChunkSize;++i){
75 std::string data(kChunkSize,'a'+ i);
76 ASSERT_TRUE(writing_blob->Write(i* kChunkSize, base::as_byte_span(data)));
77}
78 writing_blob.reset();
79
80// Read the blob.
81 std::optional<StreamingBlobHandle> reading_blob= db_.GetStreamingBlob(
82"foo","data", db_.GetLastInsertRowId(),/*readonly=*/true);
83 ASSERT_TRUE(reading_blob.has_value());
84 std::string read_data(kBlobSize,'X');
85// Toss in an offset to ensure it works correctly.
86 ASSERT_TRUE(reading_blob->Read(
877, base::as_writable_byte_span(read_data).subspan(10U, kBlobSize-20)));
88 EXPECT_EQ(
89"XXXXXXXXXXabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiii"
90"iiiiijjjjjjjjkkkkkkkkllllllllmmmmmmmmnnnnnnnnoooXXXXXXXXXX",
91 read_data);
92
93// Make sure that committing this transaction doesn't affect the validity of
94// the blob handle.
95 transaction->Commit();
96 transaction.reset();
97
98 EXPECT_TRUE(reading_blob->Read(0, base::as_writable_byte_span(read_data)));
99 EXPECT_EQ(
100"aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhhiiiiii"
101"iijjjjjjjjkkkkkkkkllllllllmmmmmmmmnnnnnnnnoooooooopppppppp",
102 read_data);
103
104// The blob's existence prevents closing the DB. Normally Chromium code
105// closes the DB via Database::Close(); doing so now would hit a DCHECK.
106 ASSERT_EQ(ToSqliteResultCode(sqlite3_close(db_.db_.get())),
107SqliteResultCode::kBusy);
108
109// Coverage for move ctor.
110auto reading_blob_owned=
111 std::make_unique<StreamingBlobHandle>(*std::move(reading_blob));
112
113// The blob handle expires when the row it's in is updated. This means Read()
114// will error out. This scenario is assumed to be a programming error.
115StreamingBlobHandle* reading_blob_ptr= reading_blob_owned.get();
116int sqlite_callback_error= SQLITE_OK;
117 db_.set_error_callback(base::BindRepeating(
118 base::BindLambdaForTesting(
119[&sqlite_callback_error](
120Database& database,
121 std::unique_ptr<StreamingBlobHandle> owned_blob,int sqlite_error,
122Statement* statement){
123 sqlite_callback_error= sqlite_error;
124 EXPECT_EQ(statement,nullptr);
125// Many clients will close the database in the error
126// callback. This call would present a problem if the blob
127// handle were still open.
128 database.Close();
129// Many clients will also delete the StreamingBlobHandle here,
130// inside the error callback; make sure nothing bad happens.
131}),
132 std::ref(db_), base::Passed(std::move(reading_blob_owned))));
133 transaction.emplace(&db_);
134 ASSERT_TRUE(transaction->Begin());
135{
136Statement statement(db_.GetCachedStatement(
137 SQL_FROM_HERE,"UPDATE foo SET timestamp = ? WHERE id = ?"));
138 statement.BindTime(0, base::Time::Now()+ base::Milliseconds(100));
139 statement.BindInt64(1, row_id);
140 ASSERT_TRUE(statement.Run());
141}
142 EXPECT_EQ(sqlite_callback_error, SQLITE_OK);
143 EXPECT_FALSE(
144 reading_blob_ptr->Read(0, base::as_writable_byte_span(read_data)));
145 EXPECT_EQ(sqlite_callback_error, SQLITE_ABORT);
146}
147
148}// namespace sql

[8]ページ先頭

©2009-2025 Movatter.jp