blob: 5ac65472adb6f01d84b2a12814d4a8c8128b29c5 [file] [log] [blame]
// Copyright 2016 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 "container_utils/device_jail/permission_broker_client.h"
#include <memory>
#include <base/at_exit.h>
#include <base/bind.h>
#include <base/memory/ptr_util.h>
#include <base/memory/ref_counted.h>
#include <brillo/message_loops/base_message_loop.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/file_descriptor.h>
#include <dbus/message.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_object_proxy.h>
#include <gtest/gtest.h>
namespace device_jail {
namespace {
using testing::AnyNumber;
using testing::Return;
using testing::_;
const char kTestDevicePath[] = "/test/device";
MATCHER(IsOpenPathMethodCall, "") {
return arg->GetInterface() == permission_broker::kPermissionBrokerInterface
&& arg->GetMember() == permission_broker::kOpenPath;
}
class PermissionBrokerClientTest : public testing::Test {
public:
void SetUp() override {
dbus::Bus::Options options;
options.bus_type = dbus::Bus::SYSTEM;
bus_ = new dbus::MockBus(options);
// By default, don't worry about threading assertions.
EXPECT_CALL(*bus_, AssertOnOriginThread()).Times(AnyNumber());
EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
// Use a mock object proxy.
using permission_broker::kPermissionBrokerServiceName;
using permission_broker::kPermissionBrokerServicePath;
mock_object_proxy_ = new dbus::MockObjectProxy(
bus_.get(),
kPermissionBrokerServiceName,
dbus::ObjectPath(kPermissionBrokerServicePath));
EXPECT_CALL(*bus_,
GetObjectProxy(kPermissionBrokerServiceName,
dbus::ObjectPath(kPermissionBrokerServicePath)))
.WillRepeatedly(Return(mock_object_proxy_.get()));
// Set up the permission broker client.
broker_client_ = base::MakeUnique<PermissionBrokerClient>(
mock_object_proxy_.get(), &message_loop_);
}
protected:
void ExpectSuccess() {
std::unique_ptr<dbus::Response> response =
dbus::Response::CreateEmpty();
dbus::MessageWriter writer(response.get());
// We need to return a valid file descriptor. It doesn't matter which one,
// so let's just use stdout.
dbus::FileDescriptor fd(1);
fd.CheckValidity();
writer.AppendFileDescriptor(fd);
EXPECT_CALL(*mock_object_proxy_,
MockCallMethodAndBlock(IsOpenPathMethodCall(), _))
.WillOnce(Return(response.release()));
}
void ExpectMalformedResponse() {
// Return a response which has no FD.
std::unique_ptr<dbus::Response> response =
dbus::Response::CreateEmpty();
dbus::MessageWriter(response.get());
EXPECT_CALL(*mock_object_proxy_,
MockCallMethodAndBlock(IsOpenPathMethodCall(), _))
.WillOnce(Return(response.release()));
}
void ExpectEmptyResponse() {
EXPECT_CALL(*mock_object_proxy_,
MockCallMethodAndBlock(IsOpenPathMethodCall(), _))
.WillOnce(Return(nullptr));
}
int OpenTestDevice() {
int ret;
broker_client_->Open(kTestDevicePath,
base::Bind(&PermissionBrokerClientTest::OpenCallback,
base::Unretained(this),
&ret));
message_loop_.RunUntilIdle();
return ret;
}
private:
void OpenCallback(int* out_fd, int fd) {
*out_fd = fd;
}
std::unique_ptr<PermissionBrokerClient> broker_client_;
base::MessageLoop message_loop_;
scoped_refptr<dbus::MockBus> bus_;
scoped_refptr<dbus::MockObjectProxy> mock_object_proxy_;
};
} // namespace
TEST_F(PermissionBrokerClientTest, ValidFD) {
ExpectSuccess();
EXPECT_GE(OpenTestDevice(), 0);
}
TEST_F(PermissionBrokerClientTest, MalformedResponse) {
ExpectMalformedResponse();
EXPECT_LT(OpenTestDevice(), 0);
}
TEST_F(PermissionBrokerClientTest, EmptyResponse) {
ExpectEmptyResponse();
EXPECT_LT(OpenTestDevice(), 0);
}
} // namespace device_jail
int main(int argc, char **argv) {
base::AtExitManager exit_manager;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}