1 // Copyright (C) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "icing/file/file-backed-proto.h"
16
17 #include "gmock/gmock.h"
18 #include "gtest/gtest.h"
19 #include "icing/document-builder.h"
20 #include "icing/portable/equals-proto.h"
21 #include "icing/proto/document.pb.h"
22 #include "icing/testing/common-matchers.h"
23 #include "icing/testing/tmp-directory.h"
24
25 using ::icing::lib::portable_equals_proto::EqualsProto;
26 using ::testing::Not;
27 using ::testing::Pointee;
28
29 namespace icing {
30 namespace lib {
31 namespace {
32
33 class FileBackedProtoTest : public ::testing::Test {
34 protected:
SetUp()35 void SetUp() override { filename_ = GetTestTempDir() + "/schema.pb"; }
36
TearDown()37 void TearDown() override { filesystem_.DeleteFile(filename_.c_str()); }
38
39 Filesystem filesystem_;
40 std::string filename_;
41 };
42
TEST_F(FileBackedProtoTest,SimpleReadWriteTest)43 TEST_F(FileBackedProtoTest, SimpleReadWriteTest) {
44 DocumentProto document =
45 DocumentBuilder().SetKey("namespace", "google.com").Build();
46
47 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
48 ICING_ASSERT_OK(file_proto.Write(absl::make_unique<DocumentProto>(document)));
49 EXPECT_THAT(file_proto.Read(), IsOkAndHolds(Pointee(EqualsProto(document))));
50 // Multiple reads work.
51 EXPECT_THAT(file_proto.Read(), IsOkAndHolds(Pointee(EqualsProto(document))));
52 EXPECT_THAT(file_proto.Read(), IsOkAndHolds(Pointee(EqualsProto(document))));
53 }
54
TEST_F(FileBackedProtoTest,DataPersistsAcrossMultipleInstancesTest)55 TEST_F(FileBackedProtoTest, DataPersistsAcrossMultipleInstancesTest) {
56 DocumentProto document =
57 DocumentBuilder().SetKey("namespace", "google.com").Build();
58
59 {
60 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
61 EXPECT_THAT(file_proto.Read(), Not(IsOk())); // Nothing to read.
62
63 ICING_ASSERT_OK(
64 file_proto.Write(absl::make_unique<DocumentProto>(document)));
65 EXPECT_THAT(file_proto.Read(),
66 IsOkAndHolds(Pointee(EqualsProto(document))));
67 }
68 {
69 // Different instance of FileBackedProto.
70 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
71 EXPECT_THAT(file_proto.Read(),
72 IsOkAndHolds(Pointee(EqualsProto(document))));
73 }
74 }
75
TEST_F(FileBackedProtoTest,MultipleUpdatesToProtoTest)76 TEST_F(FileBackedProtoTest, MultipleUpdatesToProtoTest) {
77 DocumentProto googleProto =
78 DocumentBuilder().SetKey("namespace", "google.com").Build();
79 DocumentProto youtubeProto =
80 DocumentBuilder().SetKey("namespace", "youtube.com").Build();
81 DocumentProto wazeProto =
82 DocumentBuilder().SetKey("namespace", "waze.com").Build();
83
84 {
85 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
86 ICING_ASSERT_OK(
87 file_proto.Write(absl::make_unique<DocumentProto>(googleProto)));
88 EXPECT_THAT(file_proto.Read(),
89 IsOkAndHolds(Pointee(EqualsProto(googleProto))));
90
91 ICING_ASSERT_OK(
92 file_proto.Write(absl::make_unique<DocumentProto>(youtubeProto)));
93 EXPECT_THAT(file_proto.Read(),
94 IsOkAndHolds(Pointee(EqualsProto(youtubeProto))));
95 }
96 {
97 // Different instance of FileBackedProto.
98 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
99 EXPECT_THAT(file_proto.Read(),
100 IsOkAndHolds(Pointee(EqualsProto(youtubeProto))));
101
102 ICING_ASSERT_OK(
103 file_proto.Write(absl::make_unique<DocumentProto>(wazeProto)));
104 EXPECT_THAT(file_proto.Read(),
105 IsOkAndHolds(Pointee(EqualsProto(wazeProto))));
106
107 ICING_ASSERT_OK(
108 file_proto.Write(absl::make_unique<DocumentProto>(googleProto)));
109 EXPECT_THAT(file_proto.Read(),
110 IsOkAndHolds(Pointee(EqualsProto(googleProto))));
111 }
112 }
113
TEST_F(FileBackedProtoTest,InvalidFilenameTest)114 TEST_F(FileBackedProtoTest, InvalidFilenameTest) {
115 DocumentProto document =
116 DocumentBuilder().SetKey("namespace", "google.com").Build();
117
118 FileBackedProto<DocumentProto> file_proto(filesystem_, "");
119 EXPECT_THAT(file_proto.Read(), Not(IsOk()));
120 EXPECT_THAT(file_proto.Write(absl::make_unique<DocumentProto>(document)),
121 Not(IsOk()));
122 }
123
TEST_F(FileBackedProtoTest,FileCorruptionTest)124 TEST_F(FileBackedProtoTest, FileCorruptionTest) {
125 DocumentProto document =
126 DocumentBuilder().SetKey("namespace", "google.com").Build();
127
128 {
129 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
130 ICING_ASSERT_OK(
131 file_proto.Write(absl::make_unique<DocumentProto>(document)));
132 EXPECT_THAT(file_proto.Read(),
133 IsOkAndHolds(Pointee(EqualsProto(document))));
134 }
135
136 document.set_uri("g00gle.com");
137 std::string document_str = document.SerializeAsString();
138 filesystem_.PWrite(filename_.c_str(),
139 /*offset=*/sizeof(FileBackedProto<DocumentProto>::Header),
140 document_str.data(), document_str.size());
141
142 FileBackedProto<DocumentProto> file_proto(filesystem_, filename_);
143 EXPECT_THAT(file_proto.Read(), Not(IsOk()));
144 }
145
146 } // namespace
147 } // namespace lib
148 } // namespace icing
149