blob: 768edc38d41d9fe3ee56d332a36a4fdccd060503 [file] [log] [blame]
Thieu Le3426c8f2012-01-11 17:35:11 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkova4766822011-07-07 10:42:22 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone7aa5f902011-07-11 11:13:35 -07005#include "shill/profile.h"
6
Chris Masone6791a432011-07-12 13:23:19 -07007#include <string>
8#include <vector>
9
Chris Masone6515aab2011-10-12 16:19:09 -070010#include <base/file_path.h>
Paul Stewart2ebc16d2012-08-23 10:38:39 -070011#include <base/file_util.h>
Chris Masoneb9c00592011-10-06 13:10:39 -070012#include <base/memory/scoped_ptr.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050013#include <base/stringprintf.h>
Darin Petkova4766822011-07-07 10:42:22 -070014#include <base/string_util.h>
15#include <gtest/gtest.h>
16
Chris Masone6515aab2011-10-12 16:19:09 -070017#include "shill/glib.h"
18#include "shill/key_file_store.h"
Paul Stewart75225512012-01-26 22:51:33 -080019#include "shill/mock_manager.h"
Chris Masone6791a432011-07-12 13:23:19 -070020#include "shill/mock_profile.h"
21#include "shill/mock_service.h"
Chris Masone9d779932011-08-25 16:33:41 -070022#include "shill/mock_store.h"
Chris Masone6791a432011-07-12 13:23:19 -070023#include "shill/property_store_unittest.h"
Chris Masone6515aab2011-10-12 16:19:09 -070024#include "shill/service_under_test.h"
Chris Masone6791a432011-07-12 13:23:19 -070025
26using std::set;
Darin Petkova4766822011-07-07 10:42:22 -070027using std::string;
Chris Masone6791a432011-07-12 13:23:19 -070028using std::vector;
Chris Masone9d779932011-08-25 16:33:41 -070029using testing::_;
Chris Masone6515aab2011-10-12 16:19:09 -070030using testing::Invoke;
Paul Stewart75225512012-01-26 22:51:33 -080031using testing::Mock;
Chris Masone6791a432011-07-12 13:23:19 -070032using testing::Return;
Chris Masone9d779932011-08-25 16:33:41 -070033using testing::SetArgumentPointee;
Chris Masone6791a432011-07-12 13:23:19 -070034using testing::StrictMock;
Darin Petkova4766822011-07-07 10:42:22 -070035
36namespace shill {
37
Chris Masone6791a432011-07-12 13:23:19 -070038class ProfileTest : public PropertyStoreTest {
39 public:
Chris Masone6515aab2011-10-12 16:19:09 -070040 ProfileTest() {
41 Profile::Identifier id("rather", "irrelevant");
42 profile_ = new Profile(control_interface(), manager(), id, "", false);
Chris Masone9d779932011-08-25 16:33:41 -070043 }
44
45 MockService *CreateMockService() {
Chris Masone2176a882011-09-14 22:29:15 -070046 return new StrictMock<MockService>(control_interface(),
47 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -080048 metrics(),
Chris Masone9d779932011-08-25 16:33:41 -070049 manager());
Chris Masone6791a432011-07-12 13:23:19 -070050 }
51
Chris Masone6515aab2011-10-12 16:19:09 -070052 virtual void SetUp() {
53 PropertyStoreTest::SetUp();
54 FilePath final_path(storage_path());
55 final_path = final_path.Append("test.profile");
56 scoped_ptr<KeyFileStore> storage(new KeyFileStore(&real_glib_));
57 storage->set_path(final_path);
58 ASSERT_TRUE(storage->Open());
59 profile_->set_storage(storage.release()); // Passes ownership.
60 }
61
Paul Stewart5dc40aa2011-10-28 19:43:43 -070062 bool ProfileInitStorage(const Profile::Identifier &id,
63 Profile::InitStorageOption storage_option,
64 bool save,
65 Error::Type error_type) {
66 Error error;
67 ProfileRefPtr profile(
68 new Profile(control_interface(), manager(), id, storage_path(), false));
69 bool ret = profile->InitStorage(&real_glib_, storage_option, &error);
70 EXPECT_EQ(error_type, error.type());
71 if (ret && save) {
72 EXPECT_TRUE(profile->Save());
73 }
74 return ret;
75 }
76
Chris Masone6791a432011-07-12 13:23:19 -070077 protected:
Chris Masone6515aab2011-10-12 16:19:09 -070078 GLib real_glib_;
79 ProfileRefPtr profile_;
Darin Petkova4766822011-07-07 10:42:22 -070080};
81
Paul Stewart75225512012-01-26 22:51:33 -080082TEST_F(ProfileTest, DeleteEntry) {
83 scoped_ptr<MockManager> manager(new StrictMock<MockManager>(
84 control_interface(), dispatcher(), metrics(), glib()));
85 profile_->manager_ = manager.get();
86
87 MockStore *storage(new StrictMock<MockStore>());
88 profile_->storage_.reset(storage); // Passes ownership
89 const string kEntryName("entry_name");
90
91 // If entry does not appear in storage, DeleteEntry() should return an error.
92 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
93 .WillOnce(Return(false));
94 {
95 Error error;
96 profile_->DeleteEntry(kEntryName, &error);
97 EXPECT_EQ(Error::kNotFound, error.type());
98 }
99
100 Mock::VerifyAndClearExpectations(storage);
Paul Stewart75225512012-01-26 22:51:33 -0800101
102 // If HandleProfileEntryDeletion() returns false, Profile should call
103 // DeleteGroup() itself.
Paul Stewart0756db92012-01-27 08:34:47 -0800104 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
105 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800106 EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
107 .WillOnce(Return(false));
108 EXPECT_CALL(*storage, DeleteGroup(kEntryName))
109 .WillOnce(Return(true));
Paul Stewart0756db92012-01-27 08:34:47 -0800110 EXPECT_CALL(*storage, Flush())
111 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800112 {
113 Error error;
114 profile_->DeleteEntry(kEntryName, &error);
115 EXPECT_TRUE(error.IsSuccess());
116 }
117
Paul Stewart0756db92012-01-27 08:34:47 -0800118 Mock::VerifyAndClearExpectations(storage);
119
Paul Stewart75225512012-01-26 22:51:33 -0800120 // If HandleProfileEntryDeletion() returns true, Profile should not call
121 // DeleteGroup() itself.
Paul Stewart0756db92012-01-27 08:34:47 -0800122 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
123 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800124 EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
125 .WillOnce(Return(true));
126 EXPECT_CALL(*storage, DeleteGroup(kEntryName))
127 .Times(0);
Paul Stewart0756db92012-01-27 08:34:47 -0800128 EXPECT_CALL(*storage, Flush())
129 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800130 {
131 Error error;
132 profile_->DeleteEntry(kEntryName, &error);
133 EXPECT_TRUE(error.IsSuccess());
134 }
135}
136
Darin Petkova4766822011-07-07 10:42:22 -0700137TEST_F(ProfileTest, IsValidIdentifierToken) {
138 EXPECT_FALSE(Profile::IsValidIdentifierToken(""));
139 EXPECT_FALSE(Profile::IsValidIdentifierToken(" "));
140 EXPECT_FALSE(Profile::IsValidIdentifierToken("-"));
141 EXPECT_FALSE(Profile::IsValidIdentifierToken("~"));
142 EXPECT_FALSE(Profile::IsValidIdentifierToken("_"));
143 EXPECT_TRUE(Profile::IsValidIdentifierToken("a"));
144 EXPECT_TRUE(Profile::IsValidIdentifierToken("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
145 EXPECT_TRUE(Profile::IsValidIdentifierToken("abcdefghijklmnopqrstuvwxyz"));
146 EXPECT_TRUE(Profile::IsValidIdentifierToken("0123456789"));
147}
148
149TEST_F(ProfileTest, ParseIdentifier) {
150 Profile::Identifier identifier;
151 EXPECT_FALSE(Profile::ParseIdentifier("", &identifier));
152 EXPECT_FALSE(Profile::ParseIdentifier("~", &identifier));
153 EXPECT_FALSE(Profile::ParseIdentifier("~foo", &identifier));
154 EXPECT_FALSE(Profile::ParseIdentifier("~/", &identifier));
155 EXPECT_FALSE(Profile::ParseIdentifier("~bar/", &identifier));
156 EXPECT_FALSE(Profile::ParseIdentifier("~/zoo", &identifier));
157 EXPECT_FALSE(Profile::ParseIdentifier("~./moo", &identifier));
158 EXPECT_FALSE(Profile::ParseIdentifier("~valid/?", &identifier));
159 EXPECT_FALSE(Profile::ParseIdentifier("~no//no", &identifier));
160 EXPECT_FALSE(Profile::ParseIdentifier("~no~no", &identifier));
161
162 static const char kUser[] = "user";
163 static const char kIdentifier[] = "identifier";
164 EXPECT_TRUE(Profile::ParseIdentifier(
165 base::StringPrintf("~%s/%s", kUser, kIdentifier),
166 &identifier));
167 EXPECT_EQ(kUser, identifier.user);
168 EXPECT_EQ(kIdentifier, identifier.identifier);
169
170 EXPECT_FALSE(Profile::ParseIdentifier("!", &identifier));
171 EXPECT_FALSE(Profile::ParseIdentifier("/nope", &identifier));
172
173 static const char kIdentifier2[] = "something";
174 EXPECT_TRUE(Profile::ParseIdentifier(kIdentifier2, &identifier));
175 EXPECT_EQ("", identifier.user);
176 EXPECT_EQ(kIdentifier2, identifier.identifier);
177}
178
Chris Masone7df0c672011-07-15 10:24:54 -0700179TEST_F(ProfileTest, GetFriendlyName) {
Darin Petkova4766822011-07-07 10:42:22 -0700180 static const char kUser[] = "theUser";
181 static const char kIdentifier[] = "theIdentifier";
Chris Masone6515aab2011-10-12 16:19:09 -0700182 Profile::Identifier id(kIdentifier);
Chris Masone7df0c672011-07-15 10:24:54 -0700183 ProfileRefPtr profile(
Chris Masone2176a882011-09-14 22:29:15 -0700184 new Profile(control_interface(), manager(), id, "", false));
Chris Masone7df0c672011-07-15 10:24:54 -0700185 EXPECT_EQ(kIdentifier, profile->GetFriendlyName());
186 id.user = kUser;
Chris Masone2176a882011-09-14 22:29:15 -0700187 profile = new Profile(control_interface(), manager(), id, "", false);
Chris Masone7df0c672011-07-15 10:24:54 -0700188 EXPECT_EQ(string(kUser) + "/" + kIdentifier, profile->GetFriendlyName());
Darin Petkova4766822011-07-07 10:42:22 -0700189}
190
191TEST_F(ProfileTest, GetStoragePath) {
192 static const char kUser[] = "chronos";
193 static const char kIdentifier[] = "someprofile";
Chris Masone2ae797d2011-08-23 20:41:00 -0700194 static const char kFormat[] = "/a/place/for/%s";
Darin Petkova4766822011-07-07 10:42:22 -0700195 FilePath path;
Chris Masone6515aab2011-10-12 16:19:09 -0700196 Profile::Identifier id(kIdentifier);
Chris Masone2ae797d2011-08-23 20:41:00 -0700197 ProfileRefPtr profile(
Chris Masone2176a882011-09-14 22:29:15 -0700198 new Profile(control_interface(), manager(), id, "", false));
Chris Masone2ae797d2011-08-23 20:41:00 -0700199 EXPECT_FALSE(profile->GetStoragePath(&path));
200 id.user = kUser;
201 profile =
Chris Masone2176a882011-09-14 22:29:15 -0700202 new Profile(control_interface(), manager(), id, kFormat, false);
Chris Masone2ae797d2011-08-23 20:41:00 -0700203 EXPECT_TRUE(profile->GetStoragePath(&path));
204 string suffix = base::StringPrintf("/%s.profile", kIdentifier);
205 EXPECT_EQ(base::StringPrintf(kFormat, kUser) + suffix, path.value());
Darin Petkova4766822011-07-07 10:42:22 -0700206}
207
Chris Masone6791a432011-07-12 13:23:19 -0700208TEST_F(ProfileTest, ServiceManagement) {
Chris Masone6515aab2011-10-12 16:19:09 -0700209 scoped_refptr<MockService> service1(CreateMockService());
210 scoped_refptr<MockService> service2(CreateMockService());
Chris Masone6791a432011-07-12 13:23:19 -0700211
Chris Masone6515aab2011-10-12 16:19:09 -0700212 EXPECT_CALL(*service1.get(), Save(_))
213 .WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
214 EXPECT_CALL(*service2.get(), Save(_))
215 .WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
Chris Masone6791a432011-07-12 13:23:19 -0700216
Chris Masone6515aab2011-10-12 16:19:09 -0700217 ASSERT_TRUE(profile_->AdoptService(service1));
218 ASSERT_TRUE(profile_->AdoptService(service2));
219
220 // Ensure services are in the profile now.
221 ASSERT_TRUE(profile_->ContainsService(service1));
222 ASSERT_TRUE(profile_->ContainsService(service2));
223
224 // Ensure we can't add them twice.
225 ASSERT_FALSE(profile_->AdoptService(service1));
226 ASSERT_FALSE(profile_->AdoptService(service2));
227
228 // Ensure that we can abandon individually, and that doing so is idempotent.
229 ASSERT_TRUE(profile_->AbandonService(service1));
230 ASSERT_FALSE(profile_->ContainsService(service1));
231 ASSERT_TRUE(profile_->AbandonService(service1));
232 ASSERT_TRUE(profile_->ContainsService(service2));
233
234 // Clean up.
235 ASSERT_TRUE(profile_->AbandonService(service2));
236 ASSERT_FALSE(profile_->ContainsService(service1));
237 ASSERT_FALSE(profile_->ContainsService(service2));
Chris Masone6791a432011-07-12 13:23:19 -0700238}
239
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700240TEST_F(ProfileTest, ServiceConfigure) {
Chris Masone6515aab2011-10-12 16:19:09 -0700241 ServiceRefPtr service1(new ServiceUnderTest(control_interface(),
242 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -0800243 metrics(),
Chris Masone6515aab2011-10-12 16:19:09 -0700244 manager()));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000245 service1->set_priority(service1->priority() + 1); // Change from default.
Chris Masone6515aab2011-10-12 16:19:09 -0700246 ASSERT_TRUE(profile_->AdoptService(service1));
247 ASSERT_TRUE(profile_->ContainsService(service1));
248
249 // Create new service; ask Profile to merge it with a known, matching,
250 // service; ensure that settings from |service1| wind up in |service2|.
251 ServiceRefPtr service2(new ServiceUnderTest(control_interface(),
252 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -0800253 metrics(),
Chris Masone6515aab2011-10-12 16:19:09 -0700254 manager()));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000255 int32 orig_priority = service2->priority();
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700256 ASSERT_TRUE(profile_->ConfigureService(service2));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000257 ASSERT_EQ(service1->priority(), service2->priority());
258 ASSERT_NE(orig_priority, service2->priority());
Chris Masone6515aab2011-10-12 16:19:09 -0700259
260 // Clean up.
261 ASSERT_TRUE(profile_->AbandonService(service1));
262 ASSERT_FALSE(profile_->ContainsService(service1));
263 ASSERT_FALSE(profile_->ContainsService(service2));
264}
265
266TEST_F(ProfileTest, Save) {
Chris Masone9d779932011-08-25 16:33:41 -0700267 scoped_refptr<MockService> service1(CreateMockService());
268 scoped_refptr<MockService> service2(CreateMockService());
269 EXPECT_CALL(*service1.get(), Save(_)).WillOnce(Return(true));
270 EXPECT_CALL(*service2.get(), Save(_)).WillOnce(Return(true));
271
Chris Masone6515aab2011-10-12 16:19:09 -0700272 ASSERT_TRUE(profile_->AdoptService(service1));
273 ASSERT_TRUE(profile_->AdoptService(service2));
Chris Masone9d779932011-08-25 16:33:41 -0700274
Chris Masone6515aab2011-10-12 16:19:09 -0700275 profile_->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700276}
277
Chris Masone6791a432011-07-12 13:23:19 -0700278TEST_F(ProfileTest, EntryEnumeration) {
Chris Masone6515aab2011-10-12 16:19:09 -0700279 scoped_refptr<MockService> service1(CreateMockService());
280 scoped_refptr<MockService> service2(CreateMockService());
Paul Stewart1b253142012-01-26 14:05:52 -0800281 string service1_storage_name = Technology::NameFromIdentifier(
282 Technology::kCellular) + "_1";
283 string service2_storage_name = Technology::NameFromIdentifier(
284 Technology::kCellular) + "_2";
Chris Masone6515aab2011-10-12 16:19:09 -0700285 EXPECT_CALL(*service1.get(), Save(_))
286 .WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
287 EXPECT_CALL(*service2.get(), Save(_))
288 .WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
Paul Stewart1b253142012-01-26 14:05:52 -0800289 EXPECT_CALL(*service1.get(), GetStorageIdentifier())
290 .WillRepeatedly(Return(service1_storage_name));
291 EXPECT_CALL(*service2.get(), GetStorageIdentifier())
292 .WillRepeatedly(Return(service2_storage_name));
Chris Masone6515aab2011-10-12 16:19:09 -0700293
mukesh agrawal51a7e932011-07-27 16:18:26 -0700294 string service1_name(service1->UniqueName());
295 string service2_name(service2->UniqueName());
296
Chris Masone6791a432011-07-12 13:23:19 -0700297 ASSERT_TRUE(profile_->AdoptService(service1));
298 ASSERT_TRUE(profile_->AdoptService(service2));
299
Paul Stewart1b253142012-01-26 14:05:52 -0800300 Error error;
301 ASSERT_EQ(2, profile_->EnumerateEntries(&error).size());
Chris Masone6791a432011-07-12 13:23:19 -0700302
Chris Masone6515aab2011-10-12 16:19:09 -0700303 ASSERT_TRUE(profile_->AbandonService(service1));
Paul Stewart1b253142012-01-26 14:05:52 -0800304 ASSERT_EQ(service2_storage_name, profile_->EnumerateEntries(&error)[0]);
Chris Masone6791a432011-07-12 13:23:19 -0700305
Chris Masone6515aab2011-10-12 16:19:09 -0700306 ASSERT_TRUE(profile_->AbandonService(service2));
Paul Stewart1b253142012-01-26 14:05:52 -0800307 ASSERT_EQ(0, profile_->EnumerateEntries(&error).size());
Chris Masone6791a432011-07-12 13:23:19 -0700308}
309
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700310TEST_F(ProfileTest, MatchesIdentifier) {
311 static const char kUser[] = "theUser";
312 static const char kIdentifier[] = "theIdentifier";
313 Profile::Identifier id(kUser, kIdentifier);
314 ProfileRefPtr profile(
315 new Profile(control_interface(), manager(), id, "", false));
316 EXPECT_TRUE(profile->MatchesIdentifier(id));
317 EXPECT_FALSE(profile->MatchesIdentifier(Profile::Identifier(kUser, "")));
318 EXPECT_FALSE(
319 profile->MatchesIdentifier(Profile::Identifier("", kIdentifier)));
320 EXPECT_FALSE(
321 profile->MatchesIdentifier(Profile::Identifier(kIdentifier, kUser)));
322}
323
324TEST_F(ProfileTest, InitStorage) {
325 Profile::Identifier id("theUser", "theIdentifier");
326
327 // Profile doesn't exist but we wanted it to.
328 EXPECT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
329 Error::kNotFound));
330
331 // Success case, with a side effect of creating the profile.
332 EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateNew, true,
333 Error::kSuccess));
334
335 // The results from our two test cases above will now invert since
336 // the profile now exists. First, we now succeed if we require that
337 // the profile already exist...
338 EXPECT_TRUE(ProfileInitStorage(id, Profile::kOpenExisting, false,
339 Error::kSuccess));
340
341 // And we fail if we require that it doesn't.
342 EXPECT_FALSE(ProfileInitStorage(id, Profile::kCreateNew, false,
343 Error::kAlreadyExists));
344
345 // As a sanity check, ensure "create or open" works for both profile-exists...
346 EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateOrOpenExisting, false,
347 Error::kSuccess));
348
349 // ...and for a new profile that doesn't exist.
350 Profile::Identifier id2("theUser", "theIdentifier2");
351 // Let's just make double-check that this profile really doesn't exist.
352 ASSERT_FALSE(ProfileInitStorage(id2, Profile::kOpenExisting, false,
353 Error::kNotFound));
354
355 // Then test that with "create or open" we succeed.
356 EXPECT_TRUE(ProfileInitStorage(id2, Profile::kCreateOrOpenExisting, false,
357 Error::kSuccess));
Paul Stewart2ebc16d2012-08-23 10:38:39 -0700358
359 // Corrupt the profile storage.
360 string suffix(base::StringPrintf("/%s.profile", id.identifier.c_str()));
361 FilePath final_path(
362 base::StringPrintf(storage_path().c_str(), id.user.c_str()) + suffix);
363 string data = "]corrupt_data[";
364 EXPECT_EQ(data.size(),
365 file_util::WriteFile(final_path, data.data(), data.size()));
366
367 // Then test that we fail to open this file.
368 EXPECT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
369 Error::kInternalError));
370
371 // But then on a second try the file no longer exists.
372 ASSERT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
373 Error::kNotFound));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700374}
375
Darin Petkove7c6ad32012-06-29 10:22:09 +0200376TEST_F(ProfileTest, UpdateDevice) {
377 EXPECT_FALSE(profile_->UpdateDevice(NULL));
378}
379
Paul Stewart7355ce12011-09-02 10:47:01 -0700380} // namespace shill