blob: 35a7279f3c46d23ed09c78da1dd4d72c00f5ec38 [file] [log] [blame]
// Copyright 2022 The Chromium 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 "ipcz/driver_object.h"
#include "ipcz/driver_transport.h"
#include "test/mock_driver.h"
#include "test/test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "util/ref_counted.h"
namespace ipcz {
namespace {
using testing::_;
using testing::Return;
class DriverObjectTest : public test::Test {
public:
DriverObjectTest() = default;
~DriverObjectTest() override = default;
test::MockDriver& driver() { return driver_; }
private:
::testing::StrictMock<test::MockDriver> driver_;
};
TEST_F(DriverObjectTest, Invalid) {
DriverObject object;
EXPECT_FALSE(object.is_valid());
EXPECT_EQ(nullptr, object.driver());
EXPECT_EQ(IPCZ_INVALID_DRIVER_HANDLE, object.handle());
EXPECT_FALSE(object.IsSerializable());
DriverObject other = std::move(object);
EXPECT_FALSE(object.is_valid());
EXPECT_EQ(nullptr, other.driver());
EXPECT_FALSE(other.is_valid());
EXPECT_FALSE(other.IsSerializable());
}
TEST_F(DriverObjectTest, Move) {
constexpr IpczDriverHandle kHandle = 42;
DriverObject object(test::kMockDriver, kHandle);
EXPECT_EQ(&test::kMockDriver, object.driver());
EXPECT_TRUE(object.is_valid());
EXPECT_EQ(kHandle, object.handle());
DriverObject other = std::move(object);
EXPECT_EQ(&test::kMockDriver, other.driver());
EXPECT_TRUE(other.is_valid());
EXPECT_EQ(kHandle, other.handle());
EXPECT_FALSE(object.is_valid());
EXPECT_EQ(nullptr, object.driver());
EXPECT_EQ(IPCZ_INVALID_DRIVER_HANDLE, object.handle());
// Note that releasing prevents DriverObject from invoking the driver's
// Close() on destruction.
EXPECT_EQ(kHandle, other.release());
}
TEST_F(DriverObjectTest, Reset) {
// Both explicit reset and implicit reset (i.e. DriverObject destruction) must
// invoke Close().
constexpr IpczDriverHandle kHandle = 5;
EXPECT_CALL(driver(), Close(kHandle, _, _))
.WillOnce(Return(IPCZ_RESULT_OK))
.RetiresOnSaturation();
{ DriverObject object(test::kMockDriver, kHandle); }
EXPECT_CALL(driver(), Close(kHandle, _, _))
.WillOnce(Return(IPCZ_RESULT_OK))
.RetiresOnSaturation();
{
DriverObject object(test::kMockDriver, kHandle);
object.reset();
}
}
TEST_F(DriverObjectTest, SerializableObject) {
constexpr IpczDriverHandle kHandle = 5;
DriverObject object(test::kMockDriver, kHandle);
EXPECT_CALL(driver(), Serialize(kHandle, _, _, _, _, _, _, _))
.WillOnce(Return(IPCZ_RESULT_ABORTED))
.RetiresOnSaturation();
EXPECT_TRUE(object.IsSerializable());
EXPECT_CALL(driver(), Serialize(kHandle, _, _, _, _, _, _, _))
.WillOnce(Return(IPCZ_RESULT_RESOURCE_EXHAUSTED))
.RetiresOnSaturation();
EXPECT_TRUE(object.IsSerializable());
EXPECT_CALL(driver(), Close(kHandle, _, _)).WillOnce(Return(IPCZ_RESULT_OK));
}
TEST_F(DriverObjectTest, UnserializableObject) {
constexpr IpczDriverHandle kHandle = 5;
DriverObject object(test::kMockDriver, kHandle);
EXPECT_CALL(driver(), Serialize(kHandle, _, _, _, _, _, _, _))
.WillOnce(Return(IPCZ_RESULT_INVALID_ARGUMENT));
EXPECT_FALSE(object.IsSerializable());
EXPECT_CALL(driver(), Close(kHandle, _, _)).WillOnce(Return(IPCZ_RESULT_OK));
}
TEST_F(DriverObjectTest, CanTransmit) {
constexpr IpczDriverHandle kTransport = 42;
constexpr IpczDriverHandle kHandle = 5;
auto transport = MakeRefCounted<DriverTransport>(
DriverObject(test::kMockDriver, kTransport));
DriverObject object(test::kMockDriver, kHandle);
EXPECT_CALL(driver(), Serialize(kHandle, kTransport, _, _, _, _, _, _))
.WillOnce(Return(IPCZ_RESULT_RESOURCE_EXHAUSTED));
EXPECT_TRUE(object.CanTransmitOn(*transport));
EXPECT_CALL(driver(), Close(kHandle, _, _)).WillOnce(Return(IPCZ_RESULT_OK));
EXPECT_CALL(driver(), Close(kTransport, _, _))
.WillOnce(Return(IPCZ_RESULT_OK));
}
TEST_F(DriverObjectTest, CannotTransmit) {
constexpr IpczDriverHandle kTransport = 42;
constexpr IpczDriverHandle kHandle = 5;
auto transport = MakeRefCounted<DriverTransport>(
DriverObject(test::kMockDriver, kTransport));
DriverObject object(test::kMockDriver, kHandle);
EXPECT_CALL(driver(), Serialize(kHandle, kTransport, _, _, _, _, _, _))
.WillOnce(Return(IPCZ_RESULT_PERMISSION_DENIED));
EXPECT_FALSE(object.CanTransmitOn(*transport));
EXPECT_CALL(driver(), Close(kHandle, _, _)).WillOnce(Return(IPCZ_RESULT_OK));
EXPECT_CALL(driver(), Close(kTransport, _, _))
.WillOnce(Return(IPCZ_RESULT_OK));
}
TEST_F(DriverObjectTest, GetSerializedDimensions) {
constexpr IpczDriverHandle kHandle = 5;
constexpr IpczDriverHandle kTransport = 42;
auto transport = MakeRefCounted<DriverTransport>(
DriverObject(test::kMockDriver, kTransport));
DriverObject object(test::kMockDriver, kHandle);
constexpr size_t kNumBytes = 3;
constexpr size_t kNumHandles = 7;
EXPECT_CALL(driver(), Serialize(kHandle, kTransport, _, _, _, _, _, _))
.WillOnce([&](IpczDriverHandle handle, IpczDriverHandle transport,
uint32_t flags, const void* options, void* data,
size_t* num_bytes, IpczDriverHandle* handles,
size_t* num_handles) {
EXPECT_EQ(nullptr, data);
EXPECT_EQ(nullptr, handles);
*num_bytes = kNumBytes;
*num_handles = kNumHandles;
return IPCZ_RESULT_RESOURCE_EXHAUSTED;
})
.RetiresOnSaturation();
DriverObject::SerializedDimensions dimensions =
object.GetSerializedDimensions(*transport);
EXPECT_EQ(kNumBytes, dimensions.num_bytes);
EXPECT_EQ(kNumHandles, dimensions.num_driver_handles);
EXPECT_CALL(driver(), Close(kHandle, _, _)).WillOnce(Return(IPCZ_RESULT_OK));
EXPECT_CALL(driver(), Close(kTransport, _, _))
.WillOnce(Return(IPCZ_RESULT_OK));
}
} // namespace
} // namespace ipcz