1 // Copyright 2017 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 "components/metrics/persistent_system_profile.h"
6
7 #include <memory>
8
9 #include "base/check_op.h"
10 #include "base/metrics/persistent_memory_allocator.h"
11 #include "base/rand_util.h"
12 #include "components/variations/hashing.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14
15 namespace metrics {
16
17 class PersistentSystemProfileTest : public testing::Test {
18 public:
19 const int32_t kAllocatorMemorySize = 1 << 20; // 1 MiB
20
PersistentSystemProfileTest()21 PersistentSystemProfileTest() {}
22
23 PersistentSystemProfileTest(const PersistentSystemProfileTest&) = delete;
24 PersistentSystemProfileTest& operator=(const PersistentSystemProfileTest&) =
25 delete;
26
~PersistentSystemProfileTest()27 ~PersistentSystemProfileTest() override {}
28
SetUp()29 void SetUp() override {
30 memory_allocator_ = std::make_unique<base::LocalPersistentMemoryAllocator>(
31 kAllocatorMemorySize, 0, "");
32 records_ = std::make_unique<PersistentSystemProfile::RecordAllocator>(
33 memory_allocator_.get());
34 persistent_profile_.RegisterPersistentAllocator(memory_allocator_.get());
35 }
36
TearDown()37 void TearDown() override {
38 persistent_profile_.DeregisterPersistentAllocator(memory_allocator_.get());
39 records_.reset();
40 memory_allocator_.reset();
41 }
42
WriteRecord(uint8_t type,const std::string & record)43 void WriteRecord(uint8_t type, const std::string& record) {
44 persistent_profile_.allocators_[0].Write(
45 static_cast<PersistentSystemProfile::RecordType>(type), record);
46 }
47
ReadRecord(uint8_t * type,std::string * record)48 bool ReadRecord(uint8_t* type, std::string* record) {
49 PersistentSystemProfile::RecordType rec_type;
50
51 bool success = records_->Read(&rec_type, record);
52 *type = rec_type; // Convert to uint8_t for testing.
53 return success;
54 }
55
memory_allocator()56 base::PersistentMemoryAllocator* memory_allocator() {
57 return memory_allocator_.get();
58 }
59
persistent_profile()60 PersistentSystemProfile* persistent_profile() { return &persistent_profile_; }
61
62 private:
63 PersistentSystemProfile persistent_profile_;
64 std::unique_ptr<base::PersistentMemoryAllocator> memory_allocator_;
65 std::unique_ptr<PersistentSystemProfile::RecordAllocator> records_;
66 };
67
TEST_F(PersistentSystemProfileTest,Create)68 TEST_F(PersistentSystemProfileTest, Create) {
69 uint32_t type;
70 base::PersistentMemoryAllocator::Iterator iter(memory_allocator());
71 base::PersistentMemoryAllocator::Reference ref = iter.GetNext(&type);
72 DCHECK(ref);
73 DCHECK_NE(0U, type);
74 }
75
TEST_F(PersistentSystemProfileTest,RecordSplitting)76 TEST_F(PersistentSystemProfileTest, RecordSplitting) {
77 const size_t kRecordSize = 100 << 10; // 100 KiB
78 std::vector<char> buffer;
79 buffer.resize(kRecordSize);
80 base::RandBytes(&buffer[0], kRecordSize);
81
82 WriteRecord(42, std::string(&buffer[0], kRecordSize));
83
84 uint8_t type;
85 std::string record;
86 ASSERT_TRUE(ReadRecord(&type, &record));
87 EXPECT_EQ(42U, type);
88 ASSERT_EQ(kRecordSize, record.size());
89 for (size_t i = 0; i < kRecordSize; ++i)
90 EXPECT_EQ(buffer[i], record[i]);
91 }
92
TEST_F(PersistentSystemProfileTest,ProfileStorage)93 TEST_F(PersistentSystemProfileTest, ProfileStorage) {
94 SystemProfileProto proto1;
95 SystemProfileProto::FieldTrial* trial = proto1.add_field_trial();
96 trial->set_name_id(123);
97 trial->set_group_id(456);
98
99 persistent_profile()->SetSystemProfile(proto1, false);
100
101 SystemProfileProto proto2;
102 ASSERT_TRUE(PersistentSystemProfile::HasSystemProfile(*memory_allocator()));
103 ASSERT_TRUE(
104 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
105 ASSERT_EQ(1, proto2.field_trial_size());
106 EXPECT_EQ(123U, proto2.field_trial(0).name_id());
107 EXPECT_EQ(456U, proto2.field_trial(0).group_id());
108
109 // Check that the profile can be overwritten by another incomplete profile.
110
111 trial = proto1.add_field_trial();
112 trial->set_name_id(34);
113 trial->set_group_id(50);
114
115 persistent_profile()->SetSystemProfile(proto1, false);
116
117 ASSERT_TRUE(
118 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
119 ASSERT_EQ(2, proto2.field_trial_size());
120 EXPECT_EQ(123U, proto2.field_trial(0).name_id());
121 EXPECT_EQ(456U, proto2.field_trial(0).group_id());
122 EXPECT_EQ(34U, proto2.field_trial(1).name_id());
123 EXPECT_EQ(50U, proto2.field_trial(1).group_id());
124
125 // Check that the profile can be overwritten by a complete profile.
126
127 trial = proto1.add_field_trial();
128 trial->set_name_id(78);
129 trial->set_group_id(90);
130
131 persistent_profile()->SetSystemProfile(proto1, true);
132
133 ASSERT_TRUE(
134 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
135 ASSERT_EQ(3, proto2.field_trial_size());
136 EXPECT_EQ(123U, proto2.field_trial(0).name_id());
137 EXPECT_EQ(456U, proto2.field_trial(0).group_id());
138 EXPECT_EQ(34U, proto2.field_trial(1).name_id());
139 EXPECT_EQ(50U, proto2.field_trial(1).group_id());
140 EXPECT_EQ(78U, proto2.field_trial(2).name_id());
141 EXPECT_EQ(90U, proto2.field_trial(2).group_id());
142
143 // Check that the profile won't be overwritten by a new non-complete profile.
144
145 trial = proto1.add_field_trial();
146 trial->set_name_id(0xC0DE);
147 trial->set_group_id(0xFEED);
148
149 persistent_profile()->SetSystemProfile(proto1, false);
150
151 ASSERT_TRUE(
152 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
153 ASSERT_EQ(3, proto2.field_trial_size());
154 EXPECT_EQ(123U, proto2.field_trial(0).name_id());
155 EXPECT_EQ(456U, proto2.field_trial(0).group_id());
156 EXPECT_EQ(34U, proto2.field_trial(1).name_id());
157 EXPECT_EQ(50U, proto2.field_trial(1).group_id());
158 EXPECT_EQ(78U, proto2.field_trial(2).name_id());
159 EXPECT_EQ(90U, proto2.field_trial(2).group_id());
160 }
161
TEST_F(PersistentSystemProfileTest,ProfileExtensions)162 TEST_F(PersistentSystemProfileTest, ProfileExtensions) {
163 persistent_profile()->AddFieldTrial("sna", "foo");
164
165 SystemProfileProto fetched;
166 ASSERT_FALSE(
167 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
168
169 SystemProfileProto proto;
170 SystemProfileProto::FieldTrial* trial = proto.add_field_trial();
171 trial->set_name_id(123);
172 trial->set_group_id(456);
173
174 // The system profile should now start fresh. In practice, field trials should
175 // already be properly updated in subsequent system profiles.
176 persistent_profile()->SetSystemProfile(proto, false);
177 ASSERT_TRUE(
178 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
179 ASSERT_EQ(1, fetched.field_trial_size());
180 EXPECT_EQ(123U, fetched.field_trial(0).name_id());
181 EXPECT_EQ(456U, fetched.field_trial(0).group_id());
182
183 persistent_profile()->AddFieldTrial("foo", "bar");
184 ASSERT_TRUE(
185 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
186 ASSERT_EQ(2, fetched.field_trial_size());
187 EXPECT_EQ(123U, fetched.field_trial(0).name_id());
188 EXPECT_EQ(456U, fetched.field_trial(0).group_id());
189 EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(1).name_id());
190 EXPECT_EQ(variations::HashName("bar"), fetched.field_trial(1).group_id());
191 }
192
TEST_F(PersistentSystemProfileTest,OverwriteFieldTrialsInProfile)193 TEST_F(PersistentSystemProfileTest, OverwriteFieldTrialsInProfile) {
194 // Set system profile with the field trial.
195 SystemProfileProto proto;
196 SystemProfileProto::FieldTrial* trial = proto.add_field_trial();
197 trial->set_name_id(variations::HashName("foo"));
198 trial->set_group_id(456);
199 persistent_profile()->SetSystemProfile(proto, false);
200
201 // Overwrite the same trial with different group.
202 persistent_profile()->AddFieldTrial("foo", "bar");
203
204 // The fetched profile should have the latest group name,
205 SystemProfileProto fetched;
206 ASSERT_TRUE(
207 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
208 ASSERT_EQ(1, fetched.field_trial_size());
209 EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(0).name_id());
210 EXPECT_EQ(variations::HashName("bar"), fetched.field_trial(0).group_id());
211 }
212
TEST_F(PersistentSystemProfileTest,OverwriteFieldTrials)213 TEST_F(PersistentSystemProfileTest, OverwriteFieldTrials) {
214 // Set up a non-empty system profile.
215 SystemProfileProto proto;
216 proto.set_client_uuid("id");
217 persistent_profile()->SetSystemProfile(proto, false);
218
219 // Set and overwrite the same trial with different group.
220 persistent_profile()->AddFieldTrial("foo", "bar");
221 persistent_profile()->AddFieldTrial("foo", "bar2");
222
223 // The fetched profile should have the latest group name,
224 SystemProfileProto fetched;
225 ASSERT_TRUE(
226 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
227 ASSERT_EQ(1, fetched.field_trial_size());
228 EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(0).name_id());
229 EXPECT_EQ(variations::HashName("bar2"), fetched.field_trial(0).group_id());
230 }
231
TEST_F(PersistentSystemProfileTest,DeleteFieldTrials)232 TEST_F(PersistentSystemProfileTest, DeleteFieldTrials) {
233 // Set up a non-empty system profile.
234 SystemProfileProto proto;
235 proto.set_client_uuid("id");
236 persistent_profile()->SetSystemProfile(proto, false);
237
238 // Set and delete the trial.
239 persistent_profile()->AddFieldTrial("foo", "bar");
240 persistent_profile()->RemoveFieldTrial("foo");
241
242 // The fetched profile should not have the deleted trial.
243 SystemProfileProto fetched;
244 ASSERT_TRUE(
245 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
246 ASSERT_EQ(0, fetched.field_trial_size());
247
248 // Reset the trial and the fetched profile should have the latest group name.
249 persistent_profile()->AddFieldTrial("foo", "bar2");
250 ASSERT_TRUE(
251 PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
252 ASSERT_EQ(1, fetched.field_trial_size());
253 EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(0).name_id());
254 EXPECT_EQ(variations::HashName("bar2"), fetched.field_trial(0).group_id());
255 }
256
257 } // namespace metrics
258