538 lines
20 KiB
C++
538 lines
20 KiB
C++
//
|
|
// Copyright (C) 2012 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
|
|
#include "shill/profile.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <base/files/file_util.h>
|
|
#include <base/strings/stringprintf.h>
|
|
#include <base/strings/string_util.h>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "shill/fake_store.h"
|
|
#include "shill/mock_manager.h"
|
|
#include "shill/mock_metrics.h"
|
|
#include "shill/mock_profile.h"
|
|
#include "shill/mock_service.h"
|
|
#include "shill/mock_store.h"
|
|
#include "shill/property_store_unittest.h"
|
|
#include "shill/service_under_test.h"
|
|
#include "shill/store_factory.h"
|
|
|
|
using base::FilePath;
|
|
using std::set;
|
|
using std::string;
|
|
using std::vector;
|
|
using testing::_;
|
|
using testing::Invoke;
|
|
using testing::Mock;
|
|
using testing::Return;
|
|
using testing::SetArgumentPointee;
|
|
using testing::StrictMock;
|
|
|
|
namespace shill {
|
|
|
|
class ProfileTest : public PropertyStoreTest {
|
|
public:
|
|
ProfileTest() : mock_metrics_(new MockMetrics(nullptr)) {
|
|
Profile::Identifier id("rather", "irrelevant");
|
|
profile_ = new Profile(
|
|
control_interface(), metrics(), manager(), id, FilePath(), false);
|
|
|
|
// Install a FakeStore by default. In tests that actually care
|
|
// about the interaction between Profile and StoreInterface, we'll
|
|
// replace this with a MockStore.
|
|
profile_->set_storage(new FakeStore());
|
|
}
|
|
|
|
MockService* CreateMockService() {
|
|
return new StrictMock<MockService>(control_interface(),
|
|
dispatcher(),
|
|
metrics(),
|
|
manager());
|
|
}
|
|
|
|
bool ProfileInitStorage(const Profile::Identifier& id,
|
|
Profile::InitStorageOption storage_option,
|
|
bool save,
|
|
Error::Type error_type) {
|
|
// Note: this code uses neither FakeStore, nor MockStore. Instead,
|
|
// it exercises a real StoreInterface implemenation.
|
|
Error error;
|
|
ProfileRefPtr profile(
|
|
new Profile(control_interface(), mock_metrics_.get(), manager(), id,
|
|
FilePath(storage_path()), false));
|
|
bool ret = profile->InitStorage(storage_option, &error);
|
|
EXPECT_EQ(error_type, error.type());
|
|
if (ret && save) {
|
|
EXPECT_TRUE(profile->Save());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
protected:
|
|
std::unique_ptr<MockMetrics> mock_metrics_;
|
|
ProfileRefPtr profile_;
|
|
};
|
|
|
|
TEST_F(ProfileTest, DeleteEntry) {
|
|
std::unique_ptr<MockManager> manager(new StrictMock<MockManager>(
|
|
control_interface(), dispatcher(), metrics()));
|
|
profile_->manager_ = manager.get();
|
|
|
|
MockStore* storage(new StrictMock<MockStore>());
|
|
profile_->storage_.reset(storage); // Passes ownership
|
|
const string kEntryName("entry_name");
|
|
|
|
// If entry does not appear in storage, DeleteEntry() should return an error.
|
|
EXPECT_CALL(*storage, ContainsGroup(kEntryName))
|
|
.WillOnce(Return(false));
|
|
{
|
|
Error error;
|
|
profile_->DeleteEntry(kEntryName, &error);
|
|
EXPECT_EQ(Error::kNotFound, error.type());
|
|
}
|
|
|
|
Mock::VerifyAndClearExpectations(storage);
|
|
|
|
// If HandleProfileEntryDeletion() returns false, Profile should call
|
|
// DeleteGroup() itself.
|
|
EXPECT_CALL(*storage, ContainsGroup(kEntryName))
|
|
.WillOnce(Return(true));
|
|
EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
|
|
.WillOnce(Return(false));
|
|
EXPECT_CALL(*storage, DeleteGroup(kEntryName))
|
|
.WillOnce(Return(true));
|
|
EXPECT_CALL(*storage, Flush())
|
|
.WillOnce(Return(true));
|
|
{
|
|
Error error;
|
|
profile_->DeleteEntry(kEntryName, &error);
|
|
EXPECT_TRUE(error.IsSuccess());
|
|
}
|
|
|
|
Mock::VerifyAndClearExpectations(storage);
|
|
|
|
// If HandleProfileEntryDeletion() returns true, Profile should not call
|
|
// DeleteGroup() itself.
|
|
EXPECT_CALL(*storage, ContainsGroup(kEntryName))
|
|
.WillOnce(Return(true));
|
|
EXPECT_CALL(*manager.get(), HandleProfileEntryDeletion(_, kEntryName))
|
|
.WillOnce(Return(true));
|
|
EXPECT_CALL(*storage, DeleteGroup(kEntryName))
|
|
.Times(0);
|
|
EXPECT_CALL(*storage, Flush())
|
|
.WillOnce(Return(true));
|
|
{
|
|
Error error;
|
|
profile_->DeleteEntry(kEntryName, &error);
|
|
EXPECT_TRUE(error.IsSuccess());
|
|
}
|
|
}
|
|
|
|
TEST_F(ProfileTest, IsValidIdentifierToken) {
|
|
EXPECT_FALSE(Profile::IsValidIdentifierToken(""));
|
|
EXPECT_FALSE(Profile::IsValidIdentifierToken(" "));
|
|
EXPECT_FALSE(Profile::IsValidIdentifierToken("-"));
|
|
EXPECT_FALSE(Profile::IsValidIdentifierToken("~"));
|
|
EXPECT_FALSE(Profile::IsValidIdentifierToken("_"));
|
|
EXPECT_TRUE(Profile::IsValidIdentifierToken("a"));
|
|
EXPECT_TRUE(Profile::IsValidIdentifierToken("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
|
|
EXPECT_TRUE(Profile::IsValidIdentifierToken("abcdefghijklmnopqrstuvwxyz"));
|
|
EXPECT_TRUE(Profile::IsValidIdentifierToken("0123456789"));
|
|
}
|
|
|
|
TEST_F(ProfileTest, ParseIdentifier) {
|
|
Profile::Identifier identifier;
|
|
EXPECT_FALSE(Profile::ParseIdentifier("", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~foo", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~/", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~bar/", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~/zoo", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~./moo", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~valid/?", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~no//no", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("~no~no", &identifier));
|
|
|
|
static const char kUser[] = "user";
|
|
static const char kIdentifier[] = "identifier";
|
|
EXPECT_TRUE(Profile::ParseIdentifier(
|
|
base::StringPrintf("~%s/%s", kUser, kIdentifier),
|
|
&identifier));
|
|
EXPECT_EQ(kUser, identifier.user);
|
|
EXPECT_EQ(kIdentifier, identifier.identifier);
|
|
|
|
EXPECT_FALSE(Profile::ParseIdentifier("!", &identifier));
|
|
EXPECT_FALSE(Profile::ParseIdentifier("/nope", &identifier));
|
|
|
|
static const char kIdentifier2[] = "something";
|
|
EXPECT_TRUE(Profile::ParseIdentifier(kIdentifier2, &identifier));
|
|
EXPECT_EQ("", identifier.user);
|
|
EXPECT_EQ(kIdentifier2, identifier.identifier);
|
|
}
|
|
|
|
TEST_F(ProfileTest, IdentifierToString) {
|
|
Profile::Identifier identifier;
|
|
static const char kUser[] = "user";
|
|
static const char kIdentifier[] = "identifier";
|
|
identifier.user = kUser;
|
|
identifier.identifier = kIdentifier;
|
|
EXPECT_EQ(base::StringPrintf("~%s/%s", kUser, kIdentifier),
|
|
Profile::IdentifierToString(identifier));
|
|
}
|
|
|
|
TEST_F(ProfileTest, GetFriendlyName) {
|
|
static const char kUser[] = "theUser";
|
|
static const char kIdentifier[] = "theIdentifier";
|
|
Profile::Identifier id(kIdentifier);
|
|
ProfileRefPtr profile(new Profile(
|
|
control_interface(), metrics(), manager(), id, FilePath(), false));
|
|
EXPECT_EQ(kIdentifier, profile->GetFriendlyName());
|
|
id.user = kUser;
|
|
profile = new Profile(
|
|
control_interface(), metrics(), manager(), id, FilePath(), false);
|
|
EXPECT_EQ(string(kUser) + "/" + kIdentifier, profile->GetFriendlyName());
|
|
}
|
|
|
|
TEST_F(ProfileTest, GetStoragePath) {
|
|
static const char kUser[] = "chronos";
|
|
static const char kIdentifier[] = "someprofile";
|
|
static const char kDirectory[] = "/a/place/for/";
|
|
Profile::Identifier id(kIdentifier);
|
|
ProfileRefPtr profile(new Profile(
|
|
control_interface(), metrics(), manager(), id, FilePath(), false));
|
|
EXPECT_TRUE(profile->persistent_profile_path_.empty());
|
|
id.user = kUser;
|
|
profile = new Profile(
|
|
control_interface(), metrics(), manager(), id, FilePath(kDirectory),
|
|
false);
|
|
#if defined(ENABLE_JSON_STORE)
|
|
EXPECT_EQ("/a/place/for/chronos/someprofile.profile.json",
|
|
profile->persistent_profile_path_.value());
|
|
#else
|
|
EXPECT_EQ("/a/place/for/chronos/someprofile.profile",
|
|
profile->persistent_profile_path_.value());
|
|
#endif
|
|
}
|
|
|
|
TEST_F(ProfileTest, ServiceManagement) {
|
|
scoped_refptr<MockService> service1(CreateMockService());
|
|
scoped_refptr<MockService> service2(CreateMockService());
|
|
|
|
EXPECT_CALL(*service1.get(), Save(_))
|
|
.WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
|
|
EXPECT_CALL(*service2.get(), Save(_))
|
|
.WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
|
|
|
|
ASSERT_TRUE(profile_->AdoptService(service1));
|
|
ASSERT_TRUE(profile_->AdoptService(service2));
|
|
|
|
// Ensure services are in the profile now.
|
|
ASSERT_TRUE(profile_->ContainsService(service1));
|
|
ASSERT_TRUE(profile_->ContainsService(service2));
|
|
|
|
// Ensure we can't add them twice.
|
|
ASSERT_FALSE(profile_->AdoptService(service1));
|
|
ASSERT_FALSE(profile_->AdoptService(service2));
|
|
|
|
// Ensure that we can abandon individually, and that doing so is idempotent.
|
|
ASSERT_TRUE(profile_->AbandonService(service1));
|
|
ASSERT_FALSE(profile_->ContainsService(service1));
|
|
ASSERT_TRUE(profile_->AbandonService(service1));
|
|
ASSERT_TRUE(profile_->ContainsService(service2));
|
|
|
|
// Clean up.
|
|
ASSERT_TRUE(profile_->AbandonService(service2));
|
|
ASSERT_FALSE(profile_->ContainsService(service1));
|
|
ASSERT_FALSE(profile_->ContainsService(service2));
|
|
}
|
|
|
|
TEST_F(ProfileTest, ServiceConfigure) {
|
|
ServiceRefPtr service1(new ServiceUnderTest(control_interface(),
|
|
dispatcher(),
|
|
metrics(),
|
|
manager()));
|
|
// Change priority from default.
|
|
service1->SetPriority(service1->priority() + 1, nullptr);
|
|
ASSERT_TRUE(profile_->AdoptService(service1));
|
|
ASSERT_TRUE(profile_->ContainsService(service1));
|
|
|
|
// Create new service; ask Profile to merge it with a known, matching,
|
|
// service; ensure that settings from |service1| wind up in |service2|.
|
|
ServiceRefPtr service2(new ServiceUnderTest(control_interface(),
|
|
dispatcher(),
|
|
metrics(),
|
|
manager()));
|
|
int32_t orig_priority = service2->priority();
|
|
ASSERT_TRUE(profile_->ConfigureService(service2));
|
|
ASSERT_EQ(service1->priority(), service2->priority());
|
|
ASSERT_NE(orig_priority, service2->priority());
|
|
|
|
// Clean up.
|
|
ASSERT_TRUE(profile_->AbandonService(service1));
|
|
ASSERT_FALSE(profile_->ContainsService(service1));
|
|
ASSERT_FALSE(profile_->ContainsService(service2));
|
|
}
|
|
|
|
TEST_F(ProfileTest, Save) {
|
|
scoped_refptr<MockService> service1(CreateMockService());
|
|
scoped_refptr<MockService> service2(CreateMockService());
|
|
EXPECT_CALL(*service1.get(), Save(_)).WillOnce(Return(true));
|
|
EXPECT_CALL(*service2.get(), Save(_)).WillOnce(Return(true));
|
|
|
|
ASSERT_TRUE(profile_->AdoptService(service1));
|
|
ASSERT_TRUE(profile_->AdoptService(service2));
|
|
|
|
profile_->Save();
|
|
}
|
|
|
|
TEST_F(ProfileTest, EntryEnumeration) {
|
|
scoped_refptr<MockService> service1(CreateMockService());
|
|
scoped_refptr<MockService> service2(CreateMockService());
|
|
string service1_storage_name = Technology::NameFromIdentifier(
|
|
Technology::kCellular) + "_1";
|
|
string service2_storage_name = Technology::NameFromIdentifier(
|
|
Technology::kCellular) + "_2";
|
|
EXPECT_CALL(*service1.get(), Save(_))
|
|
.WillRepeatedly(Invoke(service1.get(), &MockService::FauxSave));
|
|
EXPECT_CALL(*service2.get(), Save(_))
|
|
.WillRepeatedly(Invoke(service2.get(), &MockService::FauxSave));
|
|
EXPECT_CALL(*service1.get(), GetStorageIdentifier())
|
|
.WillRepeatedly(Return(service1_storage_name));
|
|
EXPECT_CALL(*service2.get(), GetStorageIdentifier())
|
|
.WillRepeatedly(Return(service2_storage_name));
|
|
|
|
string service1_name(service1->unique_name());
|
|
string service2_name(service2->unique_name());
|
|
|
|
ASSERT_TRUE(profile_->AdoptService(service1));
|
|
ASSERT_TRUE(profile_->AdoptService(service2));
|
|
|
|
Error error;
|
|
ASSERT_EQ(2, profile_->EnumerateEntries(&error).size());
|
|
|
|
ASSERT_TRUE(profile_->AbandonService(service1));
|
|
ASSERT_EQ(service2_storage_name, profile_->EnumerateEntries(&error)[0]);
|
|
|
|
ASSERT_TRUE(profile_->AbandonService(service2));
|
|
ASSERT_EQ(0, profile_->EnumerateEntries(&error).size());
|
|
}
|
|
|
|
TEST_F(ProfileTest, LoadUserProfileList) {
|
|
FilePath list_path(FilePath(storage_path()).Append("test.profile"));
|
|
vector<Profile::Identifier> identifiers =
|
|
Profile::LoadUserProfileList(list_path);
|
|
EXPECT_TRUE(identifiers.empty());
|
|
|
|
const char kUser0[] = "scarecrow";
|
|
const char kUser1[] = "jeans";
|
|
const char kIdentifier0[] = "rattlesnake";
|
|
const char kIdentifier1[] = "ceiling";
|
|
const char kHash0[] = "neighbors";
|
|
string data(base::StringPrintf("\n"
|
|
"~userbut/nospacehere\n"
|
|
"defaultprofile notaccepted\n"
|
|
"~%s/%s %s\n"
|
|
"~userbutno/hash\n"
|
|
" ~dontaccept/leadingspaces hash\n"
|
|
"~this_username_fails_to_parse/id hash\n"
|
|
"~%s/%s \n\n",
|
|
kUser0, kIdentifier0, kHash0,
|
|
kUser1, kIdentifier1));
|
|
EXPECT_EQ(data.size(), base::WriteFile(list_path, data.data(), data.size()));
|
|
identifiers = Profile::LoadUserProfileList(list_path);
|
|
EXPECT_EQ(2, identifiers.size());
|
|
EXPECT_EQ(kUser0, identifiers[0].user);
|
|
EXPECT_EQ(kIdentifier0, identifiers[0].identifier);
|
|
EXPECT_EQ(kHash0, identifiers[0].user_hash);
|
|
EXPECT_EQ(kUser1, identifiers[1].user);
|
|
EXPECT_EQ(kIdentifier1, identifiers[1].identifier);
|
|
EXPECT_EQ("", identifiers[1].user_hash);
|
|
}
|
|
|
|
TEST_F(ProfileTest, SaveUserProfileList) {
|
|
const char kUser0[] = "user0";
|
|
const char kIdentifier0[] = "id0";
|
|
Profile::Identifier id0(kUser0, kIdentifier0);
|
|
const char kHash0[] = "hash0";
|
|
id0.user_hash = kHash0;
|
|
vector<ProfileRefPtr> profiles;
|
|
profiles.push_back(new Profile(
|
|
control_interface(), metrics(), manager(), id0, FilePath(), false));
|
|
|
|
const char kUser1[] = "user1";
|
|
const char kIdentifier1[] = "id1";
|
|
Profile::Identifier id1(kUser1, kIdentifier1);
|
|
const char kHash1[] = "hash1";
|
|
id1.user_hash = kHash1;
|
|
profiles.push_back(new Profile(
|
|
control_interface(), metrics(), manager(), id1, FilePath(), false));
|
|
|
|
|
|
const char kIdentifier2[] = "id2";
|
|
Profile::Identifier id2("", kIdentifier2);
|
|
const char kHash2[] = "hash2";
|
|
id1.user_hash = kHash2;
|
|
profiles.push_back(new Profile(
|
|
control_interface(), metrics(), manager(), id2, FilePath(), false));
|
|
|
|
FilePath list_path(FilePath(storage_path()).Append("test.profile"));
|
|
EXPECT_TRUE(Profile::SaveUserProfileList(list_path, profiles));
|
|
|
|
string profile_data;
|
|
EXPECT_TRUE(base::ReadFileToString(list_path, &profile_data));
|
|
EXPECT_EQ(base::StringPrintf("~%s/%s %s\n~%s/%s %s\n",
|
|
kUser0, kIdentifier0, kHash0,
|
|
kUser1, kIdentifier1, kHash1),
|
|
profile_data);
|
|
}
|
|
|
|
TEST_F(ProfileTest, MatchesIdentifier) {
|
|
static const char kUser[] = "theUser";
|
|
static const char kIdentifier[] = "theIdentifier";
|
|
Profile::Identifier id(kUser, kIdentifier);
|
|
ProfileRefPtr profile(new Profile(
|
|
control_interface(), metrics(), manager(), id, FilePath(), false));
|
|
EXPECT_TRUE(profile->MatchesIdentifier(id));
|
|
EXPECT_FALSE(profile->MatchesIdentifier(Profile::Identifier(kUser, "")));
|
|
EXPECT_FALSE(
|
|
profile->MatchesIdentifier(Profile::Identifier("", kIdentifier)));
|
|
EXPECT_FALSE(
|
|
profile->MatchesIdentifier(Profile::Identifier(kIdentifier, kUser)));
|
|
}
|
|
|
|
TEST_F(ProfileTest, InitStorage) {
|
|
Profile::Identifier id("theUser", "theIdentifier");
|
|
ASSERT_TRUE(base::CreateDirectory(
|
|
base::FilePath(storage_path()).Append("theUser")));
|
|
|
|
// Profile doesn't exist but we wanted it to.
|
|
EXPECT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
|
|
Error::kNotFound));
|
|
|
|
// Success case, with a side effect of creating the profile.
|
|
EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateNew, true,
|
|
Error::kSuccess));
|
|
|
|
// The results from our two test cases above will now invert since
|
|
// the profile now exists. First, we now succeed if we require that
|
|
// the profile already exist...
|
|
EXPECT_TRUE(ProfileInitStorage(id, Profile::kOpenExisting, false,
|
|
Error::kSuccess));
|
|
|
|
// And we fail if we require that it doesn't.
|
|
EXPECT_FALSE(ProfileInitStorage(id, Profile::kCreateNew, false,
|
|
Error::kAlreadyExists));
|
|
|
|
// As a sanity check, ensure "create or open" works for both profile-exists...
|
|
EXPECT_TRUE(ProfileInitStorage(id, Profile::kCreateOrOpenExisting, false,
|
|
Error::kSuccess));
|
|
|
|
// ...and for a new profile that doesn't exist.
|
|
Profile::Identifier id2("theUser", "theIdentifier2");
|
|
// Let's just make double-check that this profile really doesn't exist.
|
|
ASSERT_FALSE(ProfileInitStorage(id2, Profile::kOpenExisting, false,
|
|
Error::kNotFound));
|
|
|
|
// Then test that with "create or open" we succeed.
|
|
EXPECT_TRUE(ProfileInitStorage(id2, Profile::kCreateOrOpenExisting, false,
|
|
Error::kSuccess));
|
|
|
|
// Corrupt the profile storage.
|
|
FilePath final_path(
|
|
base::StringPrintf("%s/%s/%s.profile", storage_path().c_str(),
|
|
id.user.c_str(), id.identifier.c_str()));
|
|
#ifdef ENABLE_JSON_STORE
|
|
final_path = final_path.AddExtension("json");
|
|
#endif
|
|
string data = "]corrupt_data[";
|
|
EXPECT_EQ(data.size(), base::WriteFile(final_path, data.data(), data.size()));
|
|
|
|
// Then test that we fail to open this file.
|
|
EXPECT_CALL(*mock_metrics_, NotifyCorruptedProfile());
|
|
EXPECT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
|
|
Error::kInternalError));
|
|
Mock::VerifyAndClearExpectations(mock_metrics_.get());
|
|
|
|
// But then on a second try the file no longer exists.
|
|
EXPECT_CALL(*mock_metrics_, NotifyCorruptedProfile()).Times(0);
|
|
ASSERT_FALSE(ProfileInitStorage(id, Profile::kOpenExisting, false,
|
|
Error::kNotFound));
|
|
}
|
|
|
|
TEST_F(ProfileTest, UpdateDevice) {
|
|
EXPECT_FALSE(profile_->UpdateDevice(nullptr));
|
|
}
|
|
|
|
TEST_F(ProfileTest, GetServiceFromEntry) {
|
|
std::unique_ptr<MockManager> manager(new StrictMock<MockManager>(
|
|
control_interface(), dispatcher(), metrics()));
|
|
profile_->manager_ = manager.get();
|
|
|
|
MockStore* storage(new StrictMock<MockStore>());
|
|
profile_->storage_.reset(storage); // Passes ownership
|
|
const string kEntryName("entry_name");
|
|
|
|
// If entry does not appear in storage, GetServiceFromEntry() should return
|
|
// an error.
|
|
EXPECT_CALL(*storage, ContainsGroup(kEntryName))
|
|
.WillOnce(Return(false));
|
|
{
|
|
Error error;
|
|
profile_->GetServiceFromEntry(kEntryName, &error);
|
|
EXPECT_EQ(Error::kNotFound, error.type());
|
|
}
|
|
Mock::VerifyAndClearExpectations(storage);
|
|
|
|
EXPECT_CALL(*storage, ContainsGroup(kEntryName))
|
|
.WillRepeatedly(Return(true));
|
|
|
|
// Service entry already registered with the manager, the registered service
|
|
// is returned.
|
|
scoped_refptr<MockService> registered_service(CreateMockService());
|
|
EXPECT_CALL(*manager.get(),
|
|
GetServiceWithStorageIdentifier(profile_, kEntryName, _))
|
|
.WillOnce(Return(registered_service));
|
|
{
|
|
Error error;
|
|
EXPECT_EQ(registered_service,
|
|
profile_->GetServiceFromEntry(kEntryName, &error));
|
|
EXPECT_TRUE(error.IsSuccess());
|
|
}
|
|
Mock::VerifyAndClearExpectations(manager.get());
|
|
|
|
// Service entry not registered with the manager, a temporary service is
|
|
// created/returned.
|
|
scoped_refptr<MockService> temporary_service(CreateMockService());
|
|
EXPECT_CALL(*manager.get(),
|
|
GetServiceWithStorageIdentifier(profile_, kEntryName, _))
|
|
.WillOnce(Return(nullptr));
|
|
EXPECT_CALL(*manager.get(),
|
|
CreateTemporaryServiceFromProfile(profile_, kEntryName, _))
|
|
.WillOnce(Return(temporary_service));
|
|
{
|
|
Error error;
|
|
EXPECT_EQ(temporary_service,
|
|
profile_->GetServiceFromEntry(kEntryName, &error));
|
|
EXPECT_TRUE(error.IsSuccess());
|
|
}
|
|
Mock::VerifyAndClearExpectations(manager.get());
|
|
}
|
|
|
|
} // namespace shill
|