blob: 47c7d15a0ef1098622a38870faeb081adc0ac63e [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "federated/session_manager_proxy.h"
#include <memory>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <utility>
#include <vector>
#include <base/callback.h>
#include <base/check.h>
#include <base/memory/ptr_util.h>
#include <base/memory/ref_counted.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <session_manager/dbus-proxy-mocks.h>
#include "federated/utils.h"
namespace federated {
namespace {
using ::testing::_;
using ::testing::Invoke;
using ::testing::Mock;
using ::testing::SaveArg;
using ::testing::StrictMock;
using ::testing::Test;
class MockSessionManagerObserver : public SessionManagerObserverInterface {
public:
~MockSessionManagerObserver() = default;
MOCK_METHOD(void, OnSessionStarted, (), (override));
MOCK_METHOD(void, OnSessionStopped, (), (override));
};
} // namespace
class SessionManagerProxyTest : public Test {
public:
SessionManagerProxyTest()
: mock_session_manager_interface_proxy_(
new StrictMock<org::chromium::SessionManagerInterfaceProxyMock>()) {
}
SessionManagerProxyTest(const SessionManagerProxyTest&) = delete;
SessionManagerProxyTest& operator=(const SessionManagerProxyTest&) = delete;
void SetUp() override {
EXPECT_CALL(*mock_session_manager_interface_proxy_,
DoRegisterSessionStateChangedSignalHandler(_, _))
.WillOnce(SaveArg<0>(&session_state_changed_callback_));
session_manager_proxy_ = std::make_unique<SessionManagerProxy>(
base::WrapUnique<org::chromium::SessionManagerInterfaceProxyInterface>(
mock_session_manager_interface_proxy_));
}
void TearDown() override {
session_manager_proxy_.reset();
Mock::VerifyAndClearExpectations(mock_session_manager_interface_proxy_);
}
// Mocks the session state change signals
void InvokeSessionStateChange(const std::string& session_state) {
session_state_changed_callback_.Run(session_state);
}
SessionManagerProxy* session_manager_proxy() const {
CHECK_NE(session_manager_proxy_, nullptr);
return session_manager_proxy_.get();
}
// Sets the primary session and the EXPECT_CALL of RetrievePrimarySession.
void SetPrimarySession(const std::string& username,
const std::string& sanitized_username) {
primary_session_ = {username, sanitized_username};
EXPECT_CALL(*mock_session_manager_interface_proxy_,
RetrievePrimarySession(_, _, _, _))
.Times(1)
.WillOnce(
Invoke(this, &SessionManagerProxyTest::RetrievePrimarySessionImpl));
}
// Sets the session state and the EXPECT_CALL of RetrieveSessionState.
void SetSessionState(const std::string& state) {
session_state_ = state;
EXPECT_CALL(*mock_session_manager_interface_proxy_,
RetrieveSessionState(_, _, _))
.Times(1)
.WillOnce(
Invoke(this, &SessionManagerProxyTest::RetrieveSessionStateImpl));
}
private:
// Invoked when SessionManagerInterfaceProxyMock::RetrievePrimarySession() is
// called.
bool RetrievePrimarySessionImpl(std::string* const username,
std::string* const sanitized_username,
brillo::ErrorPtr* /* error */,
int /* timeout_ms */) const {
*username = primary_session_.first; // Set in SetPrimarySession().
*sanitized_username = primary_session_.second;
return true;
}
// Invoked when SessionManagerInterfaceProxyMock::RetrieveSessionState() is
// called.
bool RetrieveSessionStateImpl(std::string* const state,
brillo::ErrorPtr* /* error */,
int /* timeout_ms */) const {
*state = session_state_; // Set in SetSessionState().
return true;
}
// Primary session consists of username and sanitized_username.
std::pair<std::string, std::string> primary_session_;
std::string session_state_;
org::chromium::SessionManagerInterfaceProxyMock* const
mock_session_manager_interface_proxy_;
std::unique_ptr<SessionManagerProxy> session_manager_proxy_;
base::RepeatingCallback<void(const std::string& state)>
session_state_changed_callback_;
};
// Tests that GetSanitizedUsername can get the user_hash of current primary
// session.
TEST_F(SessionManagerProxyTest, GetSanitizedUsername) {
SetPrimarySession("user1", "hash1");
EXPECT_EQ(session_manager_proxy()->GetSanitizedUsername(), "hash1");
SetPrimarySession("user2", "hash2");
EXPECT_EQ(session_manager_proxy()->GetSanitizedUsername(), "hash2");
}
// Tests that RetrieveSessionState works. RetrieveSessionState can get whatever
// session state, although only kSessionStartedState and kSessionStoppedState
// are concerned.
TEST_F(SessionManagerProxyTest, RetrieveSessionState) {
SetSessionState(kSessionStartedState);
EXPECT_EQ(session_manager_proxy()->RetrieveSessionState(),
kSessionStartedState);
SetSessionState(kSessionStoppedState);
EXPECT_EQ(session_manager_proxy()->RetrieveSessionState(),
kSessionStoppedState);
SetSessionState("unknown_state");
EXPECT_EQ(session_manager_proxy()->RetrieveSessionState(), "unknown_state");
}
// Tests that session_manager_proxy can invoke observers when session state
// changes.
TEST_F(SessionManagerProxyTest, OnSessionStateChanged) {
StrictMock<MockSessionManagerObserver> mock_observer;
session_manager_proxy()->AddObserver(&mock_observer);
// Generates a random state array, records the counts of started and stopped
// state.
std::vector<std::string> state_vector;
int started_state_count = 0;
int stopped_state_count = 0;
const std::vector<std::string> available_states = {
kSessionStartedState, kSessionStoppedState, "unknown_state"};
static unsigned int seed = time(NULL) + 1234;
for (size_t i = 0; i < 100; i++) {
const int index = rand_r(&seed) % 3;
if (index == 0)
started_state_count++;
else if (index == 1)
stopped_state_count++;
state_vector.push_back(available_states[index]);
}
// Each time OnSessionStateChanged with state = kSessionStartedState,
// observer's OnSessionStarted is invoked.
EXPECT_CALL(mock_observer, OnSessionStarted()).Times(started_state_count);
// Each time OnSessionStateChanged with state = kSessionStoppedState,
// observer's OnSessionStopped is invoked.
EXPECT_CALL(mock_observer, OnSessionStopped()).Times(stopped_state_count);
for (const auto& state : state_vector) {
InvokeSessionStateChange(state);
}
}
} // namespace federated