blob: 89472752244c6cf756627b681db30879acb791bf [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>
Chris Masoneb9c00592011-10-06 13:10:39 -070011#include <base/memory/scoped_ptr.h>
Darin Petkova4766822011-07-07 10:42:22 -070012#include <base/string_util.h>
13#include <gtest/gtest.h>
14
Chris Masone6515aab2011-10-12 16:19:09 -070015#include "shill/glib.h"
16#include "shill/key_file_store.h"
Paul Stewart75225512012-01-26 22:51:33 -080017#include "shill/mock_manager.h"
Chris Masone6791a432011-07-12 13:23:19 -070018#include "shill/mock_profile.h"
19#include "shill/mock_service.h"
Chris Masone9d779932011-08-25 16:33:41 -070020#include "shill/mock_store.h"
Chris Masone6791a432011-07-12 13:23:19 -070021#include "shill/property_store_unittest.h"
Chris Masone6515aab2011-10-12 16:19:09 -070022#include "shill/service_under_test.h"
Chris Masone6791a432011-07-12 13:23:19 -070023
24using std::set;
Darin Petkova4766822011-07-07 10:42:22 -070025using std::string;
Chris Masone6791a432011-07-12 13:23:19 -070026using std::vector;
Chris Masone9d779932011-08-25 16:33:41 -070027using testing::_;
Chris Masone6515aab2011-10-12 16:19:09 -070028using testing::Invoke;
Paul Stewart75225512012-01-26 22:51:33 -080029using testing::Mock;
Chris Masone6791a432011-07-12 13:23:19 -070030using testing::Return;
Chris Masone9d779932011-08-25 16:33:41 -070031using testing::SetArgumentPointee;
Chris Masone6791a432011-07-12 13:23:19 -070032using testing::StrictMock;
Darin Petkova4766822011-07-07 10:42:22 -070033
34namespace shill {
35
Chris Masone6791a432011-07-12 13:23:19 -070036class ProfileTest : public PropertyStoreTest {
37 public:
Chris Masone6515aab2011-10-12 16:19:09 -070038 ProfileTest() {
39 Profile::Identifier id("rather", "irrelevant");
40 profile_ = new Profile(control_interface(), manager(), id, "", false);
Chris Masone9d779932011-08-25 16:33:41 -070041 }
42
43 MockService *CreateMockService() {
Chris Masone2176a882011-09-14 22:29:15 -070044 return new StrictMock<MockService>(control_interface(),
45 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -080046 metrics(),
Chris Masone9d779932011-08-25 16:33:41 -070047 manager());
Chris Masone6791a432011-07-12 13:23:19 -070048 }
49
Chris Masone6515aab2011-10-12 16:19:09 -070050 virtual void SetUp() {
51 PropertyStoreTest::SetUp();
52 FilePath final_path(storage_path());
53 final_path = final_path.Append("test.profile");
54 scoped_ptr<KeyFileStore> storage(new KeyFileStore(&real_glib_));
55 storage->set_path(final_path);
56 ASSERT_TRUE(storage->Open());
57 profile_->set_storage(storage.release()); // Passes ownership.
58 }
59
Paul Stewart5dc40aa2011-10-28 19:43:43 -070060 bool ProfileInitStorage(const Profile::Identifier &id,
61 Profile::InitStorageOption storage_option,
62 bool save,
63 Error::Type error_type) {
64 Error error;
65 ProfileRefPtr profile(
66 new Profile(control_interface(), manager(), id, storage_path(), false));
67 bool ret = profile->InitStorage(&real_glib_, storage_option, &error);
68 EXPECT_EQ(error_type, error.type());
69 if (ret && save) {
70 EXPECT_TRUE(profile->Save());
71 }
72 return ret;
73 }
74
Chris Masone6791a432011-07-12 13:23:19 -070075 protected:
Chris Masone6515aab2011-10-12 16:19:09 -070076 GLib real_glib_;
77 ProfileRefPtr profile_;
Darin Petkova4766822011-07-07 10:42:22 -070078};
79
Paul Stewart75225512012-01-26 22:51:33 -080080TEST_F(ProfileTest, DeleteEntry) {
81 scoped_ptr<MockManager> manager(new StrictMock<MockManager>(
82 control_interface(), dispatcher(), metrics(), glib()));
83 profile_->manager_ = manager.get();
84
85 MockStore *storage(new StrictMock<MockStore>());
86 profile_->storage_.reset(storage); // Passes ownership
87 const string kEntryName("entry_name");
88
89 // If entry does not appear in storage, DeleteEntry() should return an error.
90 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
91 .WillOnce(Return(false));
92 {
93 Error error;
94 profile_->DeleteEntry(kEntryName, &error);
95 EXPECT_EQ(Error::kNotFound, error.type());
96 }
97
98 Mock::VerifyAndClearExpectations(storage);
Paul Stewart75225512012-01-26 22:51:33 -080099
100 // If HandleProfileEntryDeletion() returns false, Profile should call
101 // DeleteGroup() itself.
Paul Stewart0756db92012-01-27 08:34:47 -0800102 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
103 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800104 EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
105 .WillOnce(Return(false));
106 EXPECT_CALL(*storage, DeleteGroup(kEntryName))
107 .WillOnce(Return(true));
Paul Stewart0756db92012-01-27 08:34:47 -0800108 EXPECT_CALL(*storage, Flush())
109 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800110 {
111 Error error;
112 profile_->DeleteEntry(kEntryName, &error);
113 EXPECT_TRUE(error.IsSuccess());
114 }
115
Paul Stewart0756db92012-01-27 08:34:47 -0800116 Mock::VerifyAndClearExpectations(storage);
117
Paul Stewart75225512012-01-26 22:51:33 -0800118 // If HandleProfileEntryDeletion() returns true, Profile should not call
119 // DeleteGroup() itself.
Paul Stewart0756db92012-01-27 08:34:47 -0800120 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
121 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800122 EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
123 .WillOnce(Return(true));
124 EXPECT_CALL(*storage, DeleteGroup(kEntryName))
125 .Times(0);
Paul Stewart0756db92012-01-27 08:34:47 -0800126 EXPECT_CALL(*storage, Flush())
127 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800128 {
129 Error error;
130 profile_->DeleteEntry(kEntryName, &error);
131 EXPECT_TRUE(error.IsSuccess());
132 }
133}
134
Darin Petkova4766822011-07-07 10:42:22 -0700135TEST_F(ProfileTest, IsValidIdentifierToken) {
136 EXPECT_FALSE(Profile::IsValidIdentifierToken(""));
137 EXPECT_FALSE(Profile::IsValidIdentifierToken(" "));
138 EXPECT_FALSE(Profile::IsValidIdentifierToken("-"));
139 EXPECT_FALSE(Profile::IsValidIdentifierToken("~"));
140 EXPECT_FALSE(Profile::IsValidIdentifierToken("_"));
141 EXPECT_TRUE(Profile::IsValidIdentifierToken("a"));
142 EXPECT_TRUE(Profile::IsValidIdentifierToken("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
143 EXPECT_TRUE(Profile::IsValidIdentifierToken("abcdefghijklmnopqrstuvwxyz"));
144 EXPECT_TRUE(Profile::IsValidIdentifierToken("0123456789"));
145}
146
147TEST_F(ProfileTest, ParseIdentifier) {
148 Profile::Identifier identifier;
149 EXPECT_FALSE(Profile::ParseIdentifier("", &identifier));
150 EXPECT_FALSE(Profile::ParseIdentifier("~", &identifier));
151 EXPECT_FALSE(Profile::ParseIdentifier("~foo", &identifier));
152 EXPECT_FALSE(Profile::ParseIdentifier("~/", &identifier));
153 EXPECT_FALSE(Profile::ParseIdentifier("~bar/", &identifier));
154 EXPECT_FALSE(Profile::ParseIdentifier("~/zoo", &identifier));
155 EXPECT_FALSE(Profile::ParseIdentifier("~./moo", &identifier));
156 EXPECT_FALSE(Profile::ParseIdentifier("~valid/?", &identifier));
157 EXPECT_FALSE(Profile::ParseIdentifier("~no//no", &identifier));
158 EXPECT_FALSE(Profile::ParseIdentifier("~no~no", &identifier));
159
160 static const char kUser[] = "user";
161 static const char kIdentifier[] = "identifier";
162 EXPECT_TRUE(Profile::ParseIdentifier(
163 base::StringPrintf("~%s/%s", kUser, kIdentifier),
164 &identifier));
165 EXPECT_EQ(kUser, identifier.user);
166 EXPECT_EQ(kIdentifier, identifier.identifier);
167
168 EXPECT_FALSE(Profile::ParseIdentifier("!", &identifier));
169 EXPECT_FALSE(Profile::ParseIdentifier("/nope", &identifier));
170
171 static const char kIdentifier2[] = "something";
172 EXPECT_TRUE(Profile::ParseIdentifier(kIdentifier2, &identifier));
173 EXPECT_EQ("", identifier.user);
174 EXPECT_EQ(kIdentifier2, identifier.identifier);
175}
176
Chris Masone7df0c672011-07-15 10:24:54 -0700177TEST_F(ProfileTest, GetFriendlyName) {
Darin Petkova4766822011-07-07 10:42:22 -0700178 static const char kUser[] = "theUser";
179 static const char kIdentifier[] = "theIdentifier";
Chris Masone6515aab2011-10-12 16:19:09 -0700180 Profile::Identifier id(kIdentifier);
Chris Masone7df0c672011-07-15 10:24:54 -0700181 ProfileRefPtr profile(
Chris Masone2176a882011-09-14 22:29:15 -0700182 new Profile(control_interface(), manager(), id, "", false));
Chris Masone7df0c672011-07-15 10:24:54 -0700183 EXPECT_EQ(kIdentifier, profile->GetFriendlyName());
184 id.user = kUser;
Chris Masone2176a882011-09-14 22:29:15 -0700185 profile = new Profile(control_interface(), manager(), id, "", false);
Chris Masone7df0c672011-07-15 10:24:54 -0700186 EXPECT_EQ(string(kUser) + "/" + kIdentifier, profile->GetFriendlyName());
Darin Petkova4766822011-07-07 10:42:22 -0700187}
188
189TEST_F(ProfileTest, GetStoragePath) {
190 static const char kUser[] = "chronos";
191 static const char kIdentifier[] = "someprofile";
Chris Masone2ae797d2011-08-23 20:41:00 -0700192 static const char kFormat[] = "/a/place/for/%s";
Darin Petkova4766822011-07-07 10:42:22 -0700193 FilePath path;
Chris Masone6515aab2011-10-12 16:19:09 -0700194 Profile::Identifier id(kIdentifier);
Chris Masone2ae797d2011-08-23 20:41:00 -0700195 ProfileRefPtr profile(
Chris Masone2176a882011-09-14 22:29:15 -0700196 new Profile(control_interface(), manager(), id, "", false));
Chris Masone2ae797d2011-08-23 20:41:00 -0700197 EXPECT_FALSE(profile->GetStoragePath(&path));
198 id.user = kUser;
199 profile =
Chris Masone2176a882011-09-14 22:29:15 -0700200 new Profile(control_interface(), manager(), id, kFormat, false);
Chris Masone2ae797d2011-08-23 20:41:00 -0700201 EXPECT_TRUE(profile->GetStoragePath(&path));
202 string suffix = base::StringPrintf("/%s.profile", kIdentifier);
203 EXPECT_EQ(base::StringPrintf(kFormat, kUser) + suffix, path.value());
Darin Petkova4766822011-07-07 10:42:22 -0700204}
205
Chris Masone6791a432011-07-12 13:23:19 -0700206TEST_F(ProfileTest, ServiceManagement) {
Chris Masone6515aab2011-10-12 16:19:09 -0700207 scoped_refptr<MockService> service1(CreateMockService());
208 scoped_refptr<MockService> service2(CreateMockService());
Chris Masone6791a432011-07-12 13:23:19 -0700209
Chris Masone6515aab2011-10-12 16:19:09 -0700210 EXPECT_CALL(*service1.get(), Save(_))
211 .WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
212 EXPECT_CALL(*service2.get(), Save(_))
213 .WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
Chris Masone6791a432011-07-12 13:23:19 -0700214
Chris Masone6515aab2011-10-12 16:19:09 -0700215 ASSERT_TRUE(profile_->AdoptService(service1));
216 ASSERT_TRUE(profile_->AdoptService(service2));
217
218 // Ensure services are in the profile now.
219 ASSERT_TRUE(profile_->ContainsService(service1));
220 ASSERT_TRUE(profile_->ContainsService(service2));
221
222 // Ensure we can't add them twice.
223 ASSERT_FALSE(profile_->AdoptService(service1));
224 ASSERT_FALSE(profile_->AdoptService(service2));
225
226 // Ensure that we can abandon individually, and that doing so is idempotent.
227 ASSERT_TRUE(profile_->AbandonService(service1));
228 ASSERT_FALSE(profile_->ContainsService(service1));
229 ASSERT_TRUE(profile_->AbandonService(service1));
230 ASSERT_TRUE(profile_->ContainsService(service2));
231
232 // Clean up.
233 ASSERT_TRUE(profile_->AbandonService(service2));
234 ASSERT_FALSE(profile_->ContainsService(service1));
235 ASSERT_FALSE(profile_->ContainsService(service2));
Chris Masone6791a432011-07-12 13:23:19 -0700236}
237
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700238TEST_F(ProfileTest, ServiceConfigure) {
Chris Masone6515aab2011-10-12 16:19:09 -0700239 ServiceRefPtr service1(new ServiceUnderTest(control_interface(),
240 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -0800241 metrics(),
Chris Masone6515aab2011-10-12 16:19:09 -0700242 manager()));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000243 service1->set_priority(service1->priority() + 1); // Change from default.
Chris Masone6515aab2011-10-12 16:19:09 -0700244 ASSERT_TRUE(profile_->AdoptService(service1));
245 ASSERT_TRUE(profile_->ContainsService(service1));
246
247 // Create new service; ask Profile to merge it with a known, matching,
248 // service; ensure that settings from |service1| wind up in |service2|.
249 ServiceRefPtr service2(new ServiceUnderTest(control_interface(),
250 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -0800251 metrics(),
Chris Masone6515aab2011-10-12 16:19:09 -0700252 manager()));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000253 int32 orig_priority = service2->priority();
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700254 ASSERT_TRUE(profile_->ConfigureService(service2));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000255 ASSERT_EQ(service1->priority(), service2->priority());
256 ASSERT_NE(orig_priority, service2->priority());
Chris Masone6515aab2011-10-12 16:19:09 -0700257
258 // Clean up.
259 ASSERT_TRUE(profile_->AbandonService(service1));
260 ASSERT_FALSE(profile_->ContainsService(service1));
261 ASSERT_FALSE(profile_->ContainsService(service2));
262}
263
264TEST_F(ProfileTest, Save) {
Chris Masone9d779932011-08-25 16:33:41 -0700265 scoped_refptr<MockService> service1(CreateMockService());
266 scoped_refptr<MockService> service2(CreateMockService());
267 EXPECT_CALL(*service1.get(), Save(_)).WillOnce(Return(true));
268 EXPECT_CALL(*service2.get(), Save(_)).WillOnce(Return(true));
269
Chris Masone6515aab2011-10-12 16:19:09 -0700270 ASSERT_TRUE(profile_->AdoptService(service1));
271 ASSERT_TRUE(profile_->AdoptService(service2));
Chris Masone9d779932011-08-25 16:33:41 -0700272
Chris Masone6515aab2011-10-12 16:19:09 -0700273 profile_->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700274}
275
Chris Masone6791a432011-07-12 13:23:19 -0700276TEST_F(ProfileTest, EntryEnumeration) {
Chris Masone6515aab2011-10-12 16:19:09 -0700277 scoped_refptr<MockService> service1(CreateMockService());
278 scoped_refptr<MockService> service2(CreateMockService());
Paul Stewart1b253142012-01-26 14:05:52 -0800279 string service1_storage_name = Technology::NameFromIdentifier(
280 Technology::kCellular) + "_1";
281 string service2_storage_name = Technology::NameFromIdentifier(
282 Technology::kCellular) + "_2";
Chris Masone6515aab2011-10-12 16:19:09 -0700283 EXPECT_CALL(*service1.get(), Save(_))
284 .WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
285 EXPECT_CALL(*service2.get(), Save(_))
286 .WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
Paul Stewart1b253142012-01-26 14:05:52 -0800287 EXPECT_CALL(*service1.get(), GetStorageIdentifier())
288 .WillRepeatedly(Return(service1_storage_name));
289 EXPECT_CALL(*service2.get(), GetStorageIdentifier())
290 .WillRepeatedly(Return(service2_storage_name));
Chris Masone6515aab2011-10-12 16:19:09 -0700291
mukesh agrawal51a7e932011-07-27 16:18:26 -0700292 string service1_name(service1->UniqueName());
293 string service2_name(service2->UniqueName());
294
Chris Masone6791a432011-07-12 13:23:19 -0700295 ASSERT_TRUE(profile_->AdoptService(service1));
296 ASSERT_TRUE(profile_->AdoptService(service2));
297
Paul Stewart1b253142012-01-26 14:05:52 -0800298 Error error;
299 ASSERT_EQ(2, profile_->EnumerateEntries(&error).size());
Chris Masone6791a432011-07-12 13:23:19 -0700300
Chris Masone6515aab2011-10-12 16:19:09 -0700301 ASSERT_TRUE(profile_->AbandonService(service1));
Paul Stewart1b253142012-01-26 14:05:52 -0800302 ASSERT_EQ(service2_storage_name, profile_->EnumerateEntries(&error)[0]);
Chris Masone6791a432011-07-12 13:23:19 -0700303
Chris Masone6515aab2011-10-12 16:19:09 -0700304 ASSERT_TRUE(profile_->AbandonService(service2));
Paul Stewart1b253142012-01-26 14:05:52 -0800305 ASSERT_EQ(0, profile_->EnumerateEntries(&error).size());
Chris Masone6791a432011-07-12 13:23:19 -0700306}
307
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700308TEST_F(ProfileTest, MatchesIdentifier) {
309 static const char kUser[] = "theUser";
310 static const char kIdentifier[] = "theIdentifier";
311 Profile::Identifier id(kUser, kIdentifier);
312 ProfileRefPtr profile(
313 new Profile(control_interface(), manager(), id, "", false));
314 EXPECT_TRUE(profile->MatchesIdentifier(id));
315 EXPECT_FALSE(profile->MatchesIdentifier(Profile::Identifier(kUser, "")));
316 EXPECT_FALSE(
317 profile->MatchesIdentifier(Profile::Identifier("", kIdentifier)));
318 EXPECT_FALSE(
319 profile->MatchesIdentifier(Profile::Identifier(kIdentifier, kUser)));
320}
321
322TEST_F(ProfileTest, InitStorage) {
323 Profile::Identifier id("theUser", "theIdentifier");
324
325 // Profile doesn't exist but we wanted it to.
326 EXPECT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
327 Error::kNotFound));
328
329 // Success case, with a side effect of creating the profile.
330 EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateNew, true,
331 Error::kSuccess));
332
333 // The results from our two test cases above will now invert since
334 // the profile now exists. First, we now succeed if we require that
335 // the profile already exist...
336 EXPECT_TRUE(ProfileInitStorage(id, Profile::kOpenExisting, false,
337 Error::kSuccess));
338
339 // And we fail if we require that it doesn't.
340 EXPECT_FALSE(ProfileInitStorage(id, Profile::kCreateNew, false,
341 Error::kAlreadyExists));
342
343 // As a sanity check, ensure "create or open" works for both profile-exists...
344 EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateOrOpenExisting, false,
345 Error::kSuccess));
346
347 // ...and for a new profile that doesn't exist.
348 Profile::Identifier id2("theUser", "theIdentifier2");
349 // Let's just make double-check that this profile really doesn't exist.
350 ASSERT_FALSE(ProfileInitStorage(id2, Profile::kOpenExisting, false,
351 Error::kNotFound));
352
353 // Then test that with "create or open" we succeed.
354 EXPECT_TRUE(ProfileInitStorage(id2, Profile::kCreateOrOpenExisting, false,
355 Error::kSuccess));
356}
357
Paul Stewart7355ce12011-09-02 10:47:01 -0700358} // namespace shill