• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21   PersistentSystemProfileTest() = default;
22 
23   PersistentSystemProfileTest(const PersistentSystemProfileTest&) = delete;
24   PersistentSystemProfileTest& operator=(const PersistentSystemProfileTest&) =
25       delete;
26 
27   ~PersistentSystemProfileTest() override = default;
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,std::string_view record)43   void WriteRecord(uint8_t type, std::string_view 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::string buffer(kRecordSize, '\0');
79   base::RandBytes(base::as_writable_byte_span(buffer));
80 
81   WriteRecord(42, buffer);
82 
83   uint8_t type;
84   std::string record;
85   ASSERT_TRUE(ReadRecord(&type, &record));
86   EXPECT_EQ(42U, type);
87   EXPECT_EQ(buffer, record);
88 }
89 
TEST_F(PersistentSystemProfileTest,ProfileStorage)90 TEST_F(PersistentSystemProfileTest, ProfileStorage) {
91   SystemProfileProto proto1;
92   SystemProfileProto::FieldTrial* trial = proto1.add_field_trial();
93   trial->set_name_id(123);
94   trial->set_group_id(456);
95 
96   persistent_profile()->SetSystemProfile(proto1, false);
97 
98   SystemProfileProto proto2;
99   ASSERT_TRUE(PersistentSystemProfile::HasSystemProfile(*memory_allocator()));
100   ASSERT_TRUE(
101       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
102   ASSERT_EQ(1, proto2.field_trial_size());
103   EXPECT_EQ(123U, proto2.field_trial(0).name_id());
104   EXPECT_EQ(456U, proto2.field_trial(0).group_id());
105 
106   // Check that the profile can be overwritten by another incomplete profile.
107 
108   trial = proto1.add_field_trial();
109   trial->set_name_id(34);
110   trial->set_group_id(50);
111 
112   persistent_profile()->SetSystemProfile(proto1, false);
113 
114   ASSERT_TRUE(
115       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
116   ASSERT_EQ(2, proto2.field_trial_size());
117   EXPECT_EQ(123U, proto2.field_trial(0).name_id());
118   EXPECT_EQ(456U, proto2.field_trial(0).group_id());
119   EXPECT_EQ(34U, proto2.field_trial(1).name_id());
120   EXPECT_EQ(50U, proto2.field_trial(1).group_id());
121 
122   // Check that the profile can be overwritten by a complete profile.
123 
124   trial = proto1.add_field_trial();
125   trial->set_name_id(78);
126   trial->set_group_id(90);
127 
128   persistent_profile()->SetSystemProfile(proto1, true);
129 
130   ASSERT_TRUE(
131       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
132   ASSERT_EQ(3, proto2.field_trial_size());
133   EXPECT_EQ(123U, proto2.field_trial(0).name_id());
134   EXPECT_EQ(456U, proto2.field_trial(0).group_id());
135   EXPECT_EQ(34U, proto2.field_trial(1).name_id());
136   EXPECT_EQ(50U, proto2.field_trial(1).group_id());
137   EXPECT_EQ(78U, proto2.field_trial(2).name_id());
138   EXPECT_EQ(90U, proto2.field_trial(2).group_id());
139 
140   // Check that the profile won't be overwritten by a new non-complete profile.
141 
142   trial = proto1.add_field_trial();
143   trial->set_name_id(0xC0DE);
144   trial->set_group_id(0xFEED);
145 
146   persistent_profile()->SetSystemProfile(proto1, false);
147 
148   ASSERT_TRUE(
149       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &proto2));
150   ASSERT_EQ(3, proto2.field_trial_size());
151   EXPECT_EQ(123U, proto2.field_trial(0).name_id());
152   EXPECT_EQ(456U, proto2.field_trial(0).group_id());
153   EXPECT_EQ(34U, proto2.field_trial(1).name_id());
154   EXPECT_EQ(50U, proto2.field_trial(1).group_id());
155   EXPECT_EQ(78U, proto2.field_trial(2).name_id());
156   EXPECT_EQ(90U, proto2.field_trial(2).group_id());
157 }
158 
TEST_F(PersistentSystemProfileTest,ProfileExtensions)159 TEST_F(PersistentSystemProfileTest, ProfileExtensions) {
160   persistent_profile()->AddFieldTrial("sna", "foo");
161 
162   SystemProfileProto fetched;
163   ASSERT_FALSE(
164       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
165 
166   SystemProfileProto proto;
167   SystemProfileProto::FieldTrial* trial = proto.add_field_trial();
168   trial->set_name_id(123);
169   trial->set_group_id(456);
170 
171   // The system profile should now start fresh. In practice, field trials should
172   // already be properly updated in subsequent system profiles.
173   persistent_profile()->SetSystemProfile(proto, false);
174   ASSERT_TRUE(
175       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
176   ASSERT_EQ(1, fetched.field_trial_size());
177   EXPECT_EQ(123U, fetched.field_trial(0).name_id());
178   EXPECT_EQ(456U, fetched.field_trial(0).group_id());
179 
180   persistent_profile()->AddFieldTrial("foo", "bar");
181   ASSERT_TRUE(
182       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
183   ASSERT_EQ(2, fetched.field_trial_size());
184   EXPECT_EQ(123U, fetched.field_trial(0).name_id());
185   EXPECT_EQ(456U, fetched.field_trial(0).group_id());
186   EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(1).name_id());
187   EXPECT_EQ(variations::HashName("bar"), fetched.field_trial(1).group_id());
188 }
189 
TEST_F(PersistentSystemProfileTest,OverwriteFieldTrialsInProfile)190 TEST_F(PersistentSystemProfileTest, OverwriteFieldTrialsInProfile) {
191   // Set system profile with the field trial.
192   SystemProfileProto proto;
193   SystemProfileProto::FieldTrial* trial = proto.add_field_trial();
194   trial->set_name_id(variations::HashName("foo"));
195   trial->set_group_id(456);
196   persistent_profile()->SetSystemProfile(proto, false);
197 
198   // Overwrite the same trial with different group.
199   persistent_profile()->AddFieldTrial("foo", "bar");
200 
201   // The fetched profile should have the latest group name,
202   SystemProfileProto fetched;
203   ASSERT_TRUE(
204       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
205   ASSERT_EQ(1, fetched.field_trial_size());
206   EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(0).name_id());
207   EXPECT_EQ(variations::HashName("bar"), fetched.field_trial(0).group_id());
208 }
209 
TEST_F(PersistentSystemProfileTest,OverwriteFieldTrials)210 TEST_F(PersistentSystemProfileTest, OverwriteFieldTrials) {
211   // Set up a non-empty system profile.
212   SystemProfileProto proto;
213   proto.set_client_uuid("id");
214   persistent_profile()->SetSystemProfile(proto, false);
215 
216   // Set and overwrite the same trial with different group.
217   persistent_profile()->AddFieldTrial("foo", "bar");
218   persistent_profile()->AddFieldTrial("foo", "bar2");
219 
220   // The fetched profile should have the latest group name,
221   SystemProfileProto fetched;
222   ASSERT_TRUE(
223       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
224   ASSERT_EQ(1, fetched.field_trial_size());
225   EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(0).name_id());
226   EXPECT_EQ(variations::HashName("bar2"), fetched.field_trial(0).group_id());
227 }
228 
TEST_F(PersistentSystemProfileTest,DeleteFieldTrials)229 TEST_F(PersistentSystemProfileTest, DeleteFieldTrials) {
230   // Set up a non-empty system profile.
231   SystemProfileProto proto;
232   proto.set_client_uuid("id");
233   persistent_profile()->SetSystemProfile(proto, false);
234 
235   // Set and delete the trial.
236   persistent_profile()->AddFieldTrial("foo", "bar");
237   persistent_profile()->RemoveFieldTrial("foo");
238 
239   // The fetched profile should not have the deleted trial.
240   SystemProfileProto fetched;
241   ASSERT_TRUE(
242       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
243   ASSERT_EQ(0, fetched.field_trial_size());
244 
245   // Reset the trial and the fetched profile should have the latest group name.
246   persistent_profile()->AddFieldTrial("foo", "bar2");
247   ASSERT_TRUE(
248       PersistentSystemProfile::GetSystemProfile(*memory_allocator(), &fetched));
249   ASSERT_EQ(1, fetched.field_trial_size());
250   EXPECT_EQ(variations::HashName("foo"), fetched.field_trial(0).name_id());
251   EXPECT_EQ(variations::HashName("bar2"), fetched.field_trial(0).group_id());
252 }
253 
254 }  // namespace metrics
255