blob: 4b45fddb33212377ad40d097bad4d7f3768d00dd [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>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/stringprintf.h>
Darin Petkova4766822011-07-07 10:42:22 -070013#include <base/string_util.h>
14#include <gtest/gtest.h>
15
Chris Masone6515aab2011-10-12 16:19:09 -070016#include "shill/glib.h"
17#include "shill/key_file_store.h"
Paul Stewart75225512012-01-26 22:51:33 -080018#include "shill/mock_manager.h"
Chris Masone6791a432011-07-12 13:23:19 -070019#include "shill/mock_profile.h"
20#include "shill/mock_service.h"
Chris Masone9d779932011-08-25 16:33:41 -070021#include "shill/mock_store.h"
Chris Masone6791a432011-07-12 13:23:19 -070022#include "shill/property_store_unittest.h"
Chris Masone6515aab2011-10-12 16:19:09 -070023#include "shill/service_under_test.h"
Chris Masone6791a432011-07-12 13:23:19 -070024
25using std::set;
Darin Petkova4766822011-07-07 10:42:22 -070026using std::string;
Chris Masone6791a432011-07-12 13:23:19 -070027using std::vector;
Chris Masone9d779932011-08-25 16:33:41 -070028using testing::_;
Chris Masone6515aab2011-10-12 16:19:09 -070029using testing::Invoke;
Paul Stewart75225512012-01-26 22:51:33 -080030using testing::Mock;
Chris Masone6791a432011-07-12 13:23:19 -070031using testing::Return;
Chris Masone9d779932011-08-25 16:33:41 -070032using testing::SetArgumentPointee;
Chris Masone6791a432011-07-12 13:23:19 -070033using testing::StrictMock;
Darin Petkova4766822011-07-07 10:42:22 -070034
35namespace shill {
36
Chris Masone6791a432011-07-12 13:23:19 -070037class ProfileTest : public PropertyStoreTest {
38 public:
Chris Masone6515aab2011-10-12 16:19:09 -070039 ProfileTest() {
40 Profile::Identifier id("rather", "irrelevant");
41 profile_ = new Profile(control_interface(), manager(), id, "", false);
Chris Masone9d779932011-08-25 16:33:41 -070042 }
43
44 MockService *CreateMockService() {
Chris Masone2176a882011-09-14 22:29:15 -070045 return new StrictMock<MockService>(control_interface(),
46 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -080047 metrics(),
Chris Masone9d779932011-08-25 16:33:41 -070048 manager());
Chris Masone6791a432011-07-12 13:23:19 -070049 }
50
Chris Masone6515aab2011-10-12 16:19:09 -070051 virtual void SetUp() {
52 PropertyStoreTest::SetUp();
53 FilePath final_path(storage_path());
54 final_path = final_path.Append("test.profile");
55 scoped_ptr<KeyFileStore> storage(new KeyFileStore(&real_glib_));
56 storage->set_path(final_path);
57 ASSERT_TRUE(storage->Open());
58 profile_->set_storage(storage.release()); // Passes ownership.
59 }
60
Paul Stewart5dc40aa2011-10-28 19:43:43 -070061 bool ProfileInitStorage(const Profile::Identifier &id,
62 Profile::InitStorageOption storage_option,
63 bool save,
64 Error::Type error_type) {
65 Error error;
66 ProfileRefPtr profile(
67 new Profile(control_interface(), manager(), id, storage_path(), false));
68 bool ret = profile->InitStorage(&real_glib_, storage_option, &error);
69 EXPECT_EQ(error_type, error.type());
70 if (ret && save) {
71 EXPECT_TRUE(profile->Save());
72 }
73 return ret;
74 }
75
Chris Masone6791a432011-07-12 13:23:19 -070076 protected:
Chris Masone6515aab2011-10-12 16:19:09 -070077 GLib real_glib_;
78 ProfileRefPtr profile_;
Darin Petkova4766822011-07-07 10:42:22 -070079};
80
Paul Stewart75225512012-01-26 22:51:33 -080081TEST_F(ProfileTest, DeleteEntry) {
82 scoped_ptr<MockManager> manager(new StrictMock<MockManager>(
83 control_interface(), dispatcher(), metrics(), glib()));
84 profile_->manager_ = manager.get();
85
86 MockStore *storage(new StrictMock<MockStore>());
87 profile_->storage_.reset(storage); // Passes ownership
88 const string kEntryName("entry_name");
89
90 // If entry does not appear in storage, DeleteEntry() should return an error.
91 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
92 .WillOnce(Return(false));
93 {
94 Error error;
95 profile_->DeleteEntry(kEntryName, &error);
96 EXPECT_EQ(Error::kNotFound, error.type());
97 }
98
99 Mock::VerifyAndClearExpectations(storage);
Paul Stewart75225512012-01-26 22:51:33 -0800100
101 // If HandleProfileEntryDeletion() returns false, Profile should call
102 // DeleteGroup() itself.
Paul Stewart0756db92012-01-27 08:34:47 -0800103 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
104 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800105 EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
106 .WillOnce(Return(false));
107 EXPECT_CALL(*storage, DeleteGroup(kEntryName))
108 .WillOnce(Return(true));
Paul Stewart0756db92012-01-27 08:34:47 -0800109 EXPECT_CALL(*storage, Flush())
110 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800111 {
112 Error error;
113 profile_->DeleteEntry(kEntryName, &error);
114 EXPECT_TRUE(error.IsSuccess());
115 }
116
Paul Stewart0756db92012-01-27 08:34:47 -0800117 Mock::VerifyAndClearExpectations(storage);
118
Paul Stewart75225512012-01-26 22:51:33 -0800119 // If HandleProfileEntryDeletion() returns true, Profile should not call
120 // DeleteGroup() itself.
Paul Stewart0756db92012-01-27 08:34:47 -0800121 EXPECT_CALL(*storage, ContainsGroup(kEntryName))
122 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800123 EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
124 .WillOnce(Return(true));
125 EXPECT_CALL(*storage, DeleteGroup(kEntryName))
126 .Times(0);
Paul Stewart0756db92012-01-27 08:34:47 -0800127 EXPECT_CALL(*storage, Flush())
128 .WillOnce(Return(true));
Paul Stewart75225512012-01-26 22:51:33 -0800129 {
130 Error error;
131 profile_->DeleteEntry(kEntryName, &error);
132 EXPECT_TRUE(error.IsSuccess());
133 }
134}
135
Darin Petkova4766822011-07-07 10:42:22 -0700136TEST_F(ProfileTest, IsValidIdentifierToken) {
137 EXPECT_FALSE(Profile::IsValidIdentifierToken(""));
138 EXPECT_FALSE(Profile::IsValidIdentifierToken(" "));
139 EXPECT_FALSE(Profile::IsValidIdentifierToken("-"));
140 EXPECT_FALSE(Profile::IsValidIdentifierToken("~"));
141 EXPECT_FALSE(Profile::IsValidIdentifierToken("_"));
142 EXPECT_TRUE(Profile::IsValidIdentifierToken("a"));
143 EXPECT_TRUE(Profile::IsValidIdentifierToken("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
144 EXPECT_TRUE(Profile::IsValidIdentifierToken("abcdefghijklmnopqrstuvwxyz"));
145 EXPECT_TRUE(Profile::IsValidIdentifierToken("0123456789"));
146}
147
148TEST_F(ProfileTest, ParseIdentifier) {
149 Profile::Identifier identifier;
150 EXPECT_FALSE(Profile::ParseIdentifier("", &identifier));
151 EXPECT_FALSE(Profile::ParseIdentifier("~", &identifier));
152 EXPECT_FALSE(Profile::ParseIdentifier("~foo", &identifier));
153 EXPECT_FALSE(Profile::ParseIdentifier("~/", &identifier));
154 EXPECT_FALSE(Profile::ParseIdentifier("~bar/", &identifier));
155 EXPECT_FALSE(Profile::ParseIdentifier("~/zoo", &identifier));
156 EXPECT_FALSE(Profile::ParseIdentifier("~./moo", &identifier));
157 EXPECT_FALSE(Profile::ParseIdentifier("~valid/?", &identifier));
158 EXPECT_FALSE(Profile::ParseIdentifier("~no//no", &identifier));
159 EXPECT_FALSE(Profile::ParseIdentifier("~no~no", &identifier));
160
161 static const char kUser[] = "user";
162 static const char kIdentifier[] = "identifier";
163 EXPECT_TRUE(Profile::ParseIdentifier(
164 base::StringPrintf("~%s/%s", kUser, kIdentifier),
165 &identifier));
166 EXPECT_EQ(kUser, identifier.user);
167 EXPECT_EQ(kIdentifier, identifier.identifier);
168
169 EXPECT_FALSE(Profile::ParseIdentifier("!", &identifier));
170 EXPECT_FALSE(Profile::ParseIdentifier("/nope", &identifier));
171
172 static const char kIdentifier2[] = "something";
173 EXPECT_TRUE(Profile::ParseIdentifier(kIdentifier2, &identifier));
174 EXPECT_EQ("", identifier.user);
175 EXPECT_EQ(kIdentifier2, identifier.identifier);
176}
177
Chris Masone7df0c672011-07-15 10:24:54 -0700178TEST_F(ProfileTest, GetFriendlyName) {
Darin Petkova4766822011-07-07 10:42:22 -0700179 static const char kUser[] = "theUser";
180 static const char kIdentifier[] = "theIdentifier";
Chris Masone6515aab2011-10-12 16:19:09 -0700181 Profile::Identifier id(kIdentifier);
Chris Masone7df0c672011-07-15 10:24:54 -0700182 ProfileRefPtr profile(
Chris Masone2176a882011-09-14 22:29:15 -0700183 new Profile(control_interface(), manager(), id, "", false));
Chris Masone7df0c672011-07-15 10:24:54 -0700184 EXPECT_EQ(kIdentifier, profile->GetFriendlyName());
185 id.user = kUser;
Chris Masone2176a882011-09-14 22:29:15 -0700186 profile = new Profile(control_interface(), manager(), id, "", false);
Chris Masone7df0c672011-07-15 10:24:54 -0700187 EXPECT_EQ(string(kUser) + "/" + kIdentifier, profile->GetFriendlyName());
Darin Petkova4766822011-07-07 10:42:22 -0700188}
189
190TEST_F(ProfileTest, GetStoragePath) {
191 static const char kUser[] = "chronos";
192 static const char kIdentifier[] = "someprofile";
Chris Masone2ae797d2011-08-23 20:41:00 -0700193 static const char kFormat[] = "/a/place/for/%s";
Darin Petkova4766822011-07-07 10:42:22 -0700194 FilePath path;
Chris Masone6515aab2011-10-12 16:19:09 -0700195 Profile::Identifier id(kIdentifier);
Chris Masone2ae797d2011-08-23 20:41:00 -0700196 ProfileRefPtr profile(
Chris Masone2176a882011-09-14 22:29:15 -0700197 new Profile(control_interface(), manager(), id, "", false));
Chris Masone2ae797d2011-08-23 20:41:00 -0700198 EXPECT_FALSE(profile->GetStoragePath(&path));
199 id.user = kUser;
200 profile =
Chris Masone2176a882011-09-14 22:29:15 -0700201 new Profile(control_interface(), manager(), id, kFormat, false);
Chris Masone2ae797d2011-08-23 20:41:00 -0700202 EXPECT_TRUE(profile->GetStoragePath(&path));
203 string suffix = base::StringPrintf("/%s.profile", kIdentifier);
204 EXPECT_EQ(base::StringPrintf(kFormat, kUser) + suffix, path.value());
Darin Petkova4766822011-07-07 10:42:22 -0700205}
206
Chris Masone6791a432011-07-12 13:23:19 -0700207TEST_F(ProfileTest, ServiceManagement) {
Chris Masone6515aab2011-10-12 16:19:09 -0700208 scoped_refptr<MockService> service1(CreateMockService());
209 scoped_refptr<MockService> service2(CreateMockService());
Chris Masone6791a432011-07-12 13:23:19 -0700210
Chris Masone6515aab2011-10-12 16:19:09 -0700211 EXPECT_CALL(*service1.get(), Save(_))
212 .WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
213 EXPECT_CALL(*service2.get(), Save(_))
214 .WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
Chris Masone6791a432011-07-12 13:23:19 -0700215
Chris Masone6515aab2011-10-12 16:19:09 -0700216 ASSERT_TRUE(profile_->AdoptService(service1));
217 ASSERT_TRUE(profile_->AdoptService(service2));
218
219 // Ensure services are in the profile now.
220 ASSERT_TRUE(profile_->ContainsService(service1));
221 ASSERT_TRUE(profile_->ContainsService(service2));
222
223 // Ensure we can't add them twice.
224 ASSERT_FALSE(profile_->AdoptService(service1));
225 ASSERT_FALSE(profile_->AdoptService(service2));
226
227 // Ensure that we can abandon individually, and that doing so is idempotent.
228 ASSERT_TRUE(profile_->AbandonService(service1));
229 ASSERT_FALSE(profile_->ContainsService(service1));
230 ASSERT_TRUE(profile_->AbandonService(service1));
231 ASSERT_TRUE(profile_->ContainsService(service2));
232
233 // Clean up.
234 ASSERT_TRUE(profile_->AbandonService(service2));
235 ASSERT_FALSE(profile_->ContainsService(service1));
236 ASSERT_FALSE(profile_->ContainsService(service2));
Chris Masone6791a432011-07-12 13:23:19 -0700237}
238
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700239TEST_F(ProfileTest, ServiceConfigure) {
Chris Masone6515aab2011-10-12 16:19:09 -0700240 ServiceRefPtr service1(new ServiceUnderTest(control_interface(),
241 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -0800242 metrics(),
Chris Masone6515aab2011-10-12 16:19:09 -0700243 manager()));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000244 service1->set_priority(service1->priority() + 1); // Change from default.
Chris Masone6515aab2011-10-12 16:19:09 -0700245 ASSERT_TRUE(profile_->AdoptService(service1));
246 ASSERT_TRUE(profile_->ContainsService(service1));
247
248 // Create new service; ask Profile to merge it with a known, matching,
249 // service; ensure that settings from |service1| wind up in |service2|.
250 ServiceRefPtr service2(new ServiceUnderTest(control_interface(),
251 dispatcher(),
Thieu Le3426c8f2012-01-11 17:35:11 -0800252 metrics(),
Chris Masone6515aab2011-10-12 16:19:09 -0700253 manager()));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000254 int32 orig_priority = service2->priority();
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700255 ASSERT_TRUE(profile_->ConfigureService(service2));
mukesh agrawal00917ce2011-11-22 23:56:55 +0000256 ASSERT_EQ(service1->priority(), service2->priority());
257 ASSERT_NE(orig_priority, service2->priority());
Chris Masone6515aab2011-10-12 16:19:09 -0700258
259 // Clean up.
260 ASSERT_TRUE(profile_->AbandonService(service1));
261 ASSERT_FALSE(profile_->ContainsService(service1));
262 ASSERT_FALSE(profile_->ContainsService(service2));
263}
264
265TEST_F(ProfileTest, Save) {
Chris Masone9d779932011-08-25 16:33:41 -0700266 scoped_refptr<MockService> service1(CreateMockService());
267 scoped_refptr<MockService> service2(CreateMockService());
268 EXPECT_CALL(*service1.get(), Save(_)).WillOnce(Return(true));
269 EXPECT_CALL(*service2.get(), Save(_)).WillOnce(Return(true));
270
Chris Masone6515aab2011-10-12 16:19:09 -0700271 ASSERT_TRUE(profile_->AdoptService(service1));
272 ASSERT_TRUE(profile_->AdoptService(service2));
Chris Masone9d779932011-08-25 16:33:41 -0700273
Chris Masone6515aab2011-10-12 16:19:09 -0700274 profile_->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700275}
276
Chris Masone6791a432011-07-12 13:23:19 -0700277TEST_F(ProfileTest, EntryEnumeration) {
Chris Masone6515aab2011-10-12 16:19:09 -0700278 scoped_refptr<MockService> service1(CreateMockService());
279 scoped_refptr<MockService> service2(CreateMockService());
Paul Stewart1b253142012-01-26 14:05:52 -0800280 string service1_storage_name = Technology::NameFromIdentifier(
281 Technology::kCellular) + "_1";
282 string service2_storage_name = Technology::NameFromIdentifier(
283 Technology::kCellular) + "_2";
Chris Masone6515aab2011-10-12 16:19:09 -0700284 EXPECT_CALL(*service1.get(), Save(_))
285 .WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
286 EXPECT_CALL(*service2.get(), Save(_))
287 .WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
Paul Stewart1b253142012-01-26 14:05:52 -0800288 EXPECT_CALL(*service1.get(), GetStorageIdentifier())
289 .WillRepeatedly(Return(service1_storage_name));
290 EXPECT_CALL(*service2.get(), GetStorageIdentifier())
291 .WillRepeatedly(Return(service2_storage_name));
Chris Masone6515aab2011-10-12 16:19:09 -0700292
mukesh agrawal51a7e932011-07-27 16:18:26 -0700293 string service1_name(service1->UniqueName());
294 string service2_name(service2->UniqueName());
295
Chris Masone6791a432011-07-12 13:23:19 -0700296 ASSERT_TRUE(profile_->AdoptService(service1));
297 ASSERT_TRUE(profile_->AdoptService(service2));
298
Paul Stewart1b253142012-01-26 14:05:52 -0800299 Error error;
300 ASSERT_EQ(2, profile_->EnumerateEntries(&error).size());
Chris Masone6791a432011-07-12 13:23:19 -0700301
Chris Masone6515aab2011-10-12 16:19:09 -0700302 ASSERT_TRUE(profile_->AbandonService(service1));
Paul Stewart1b253142012-01-26 14:05:52 -0800303 ASSERT_EQ(service2_storage_name, profile_->EnumerateEntries(&error)[0]);
Chris Masone6791a432011-07-12 13:23:19 -0700304
Chris Masone6515aab2011-10-12 16:19:09 -0700305 ASSERT_TRUE(profile_->AbandonService(service2));
Paul Stewart1b253142012-01-26 14:05:52 -0800306 ASSERT_EQ(0, profile_->EnumerateEntries(&error).size());
Chris Masone6791a432011-07-12 13:23:19 -0700307}
308
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700309TEST_F(ProfileTest, MatchesIdentifier) {
310 static const char kUser[] = "theUser";
311 static const char kIdentifier[] = "theIdentifier";
312 Profile::Identifier id(kUser, kIdentifier);
313 ProfileRefPtr profile(
314 new Profile(control_interface(), manager(), id, "", false));
315 EXPECT_TRUE(profile->MatchesIdentifier(id));
316 EXPECT_FALSE(profile->MatchesIdentifier(Profile::Identifier(kUser, "")));
317 EXPECT_FALSE(
318 profile->MatchesIdentifier(Profile::Identifier("", kIdentifier)));
319 EXPECT_FALSE(
320 profile->MatchesIdentifier(Profile::Identifier(kIdentifier, kUser)));
321}
322
323TEST_F(ProfileTest, InitStorage) {
324 Profile::Identifier id("theUser", "theIdentifier");
325
326 // Profile doesn't exist but we wanted it to.
327 EXPECT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
328 Error::kNotFound));
329
330 // Success case, with a side effect of creating the profile.
331 EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateNew, true,
332 Error::kSuccess));
333
334 // The results from our two test cases above will now invert since
335 // the profile now exists. First, we now succeed if we require that
336 // the profile already exist...
337 EXPECT_TRUE(ProfileInitStorage(id, Profile::kOpenExisting, false,
338 Error::kSuccess));
339
340 // And we fail if we require that it doesn't.
341 EXPECT_FALSE(ProfileInitStorage(id, Profile::kCreateNew, false,
342 Error::kAlreadyExists));
343
344 // As a sanity check, ensure "create or open" works for both profile-exists...
345 EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateOrOpenExisting, false,
346 Error::kSuccess));
347
348 // ...and for a new profile that doesn't exist.
349 Profile::Identifier id2("theUser", "theIdentifier2");
350 // Let's just make double-check that this profile really doesn't exist.
351 ASSERT_FALSE(ProfileInitStorage(id2, Profile::kOpenExisting, false,
352 Error::kNotFound));
353
354 // Then test that with "create or open" we succeed.
355 EXPECT_TRUE(ProfileInitStorage(id2, Profile::kCreateOrOpenExisting, false,
356 Error::kSuccess));
357}
358
Paul Stewart7355ce12011-09-02 10:47:01 -0700359} // namespace shill