blob: 92bffd7f97a739bec9ac68861b9c2a8d02664cee [file] [log] [blame]
// Copyright 2016 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 "mojo/edk/system/handle_table.h"
#include <vector>
#include "mojo/edk/system/dispatcher.h"
#include "mojo/edk/system/handle.h"
#include "mojo/edk/system/mock_simple_dispatcher.h"
#include "testing/gtest/include/gtest/gtest.h"
using mojo::util::MakeRefCounted;
using mojo::util::RefPtr;
namespace mojo {
namespace system {
namespace {
TEST(HandleTableTest, Basic) {
HandleTable ht(1000u);
Handle h(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ);
MojoHandle hv = ht.AddHandle(h.Clone());
ASSERT_NE(hv, MOJO_HANDLE_INVALID);
// Save the pointer value (without taking a ref), so we can check that we get
// the same object back.
Dispatcher* dv = h.dispatcher.get();
// Reset this, to make sure that the handle table takes a ref.
h.reset();
EXPECT_EQ(MOJO_RESULT_OK, ht.GetHandle(hv, &h));
EXPECT_EQ(dv, h.dispatcher.get());
EXPECT_EQ(MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ, h.rights);
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv, &h));
ASSERT_EQ(dv, h.dispatcher.get());
EXPECT_EQ(MOJO_HANDLE_RIGHT_TRANSFER | MOJO_HANDLE_RIGHT_READ, h.rights);
EXPECT_EQ(MOJO_RESULT_OK, h.dispatcher->Close());
// We removed |hv|, so it should no longer be valid.
h.reset();
EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, ht.GetHandle(hv, &h));
}
TEST(HandleTableTest, AddHandlePair) {
HandleTable ht(1000u);
Handle h1(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_NONE);
Handle h2(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_DUPLICATE);
auto hp = ht.AddHandlePair(h1.Clone(), h2.Clone());
ASSERT_NE(hp.first, MOJO_HANDLE_INVALID);
ASSERT_NE(hp.second, MOJO_HANDLE_INVALID);
ASSERT_NE(hp.first, hp.second);
Handle h;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hp.first, &h));
ASSERT_EQ(h1, h);
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hp.second, &h));
ASSERT_EQ(h2, h);
EXPECT_EQ(MOJO_RESULT_OK, h1.dispatcher->Close());
EXPECT_EQ(MOJO_RESULT_OK, h2.dispatcher->Close());
}
TEST(HandleTableTest, AddHandleTooMany) {
HandleTable ht(2u);
Handle h1(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_NONE);
Handle h2(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_DUPLICATE);
Handle h3(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_TRANSFER);
MojoHandle hv1 = ht.AddHandle(h1.Clone());
ASSERT_NE(hv1, MOJO_HANDLE_INVALID);
MojoHandle hv2 = ht.AddHandle(h2.Clone());
ASSERT_NE(hv2, MOJO_HANDLE_INVALID);
EXPECT_NE(hv2, hv1);
// Table should be full; adding |h3| should fail.
EXPECT_EQ(MOJO_HANDLE_INVALID, ht.AddHandle(h3.Clone()));
// Remove |hv2|/|h2|.
Handle h;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv2, &h));
ASSERT_EQ(h2, h);
// Now adding |h3| should succeed.
MojoHandle hv3 = ht.AddHandle(h3.Clone());
ASSERT_NE(hv3, MOJO_HANDLE_INVALID);
EXPECT_NE(hv3, hv1);
// Note: |hv3| may be equal to |hv2| (handle values may be reused).
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv1, &h));
ASSERT_EQ(h1, h);
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv3, &h));
ASSERT_EQ(h3, h);
EXPECT_EQ(MOJO_RESULT_OK, h1.dispatcher->Close());
EXPECT_EQ(MOJO_RESULT_OK, h2.dispatcher->Close());
EXPECT_EQ(MOJO_RESULT_OK, h3.dispatcher->Close());
}
TEST(HandleTableTest, AddHandlePairTooMany) {
HandleTable ht(2u);
Handle h1(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_NONE);
Handle h2(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_TRANSFER);
Handle h3(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_READ);
Handle h4(MakeRefCounted<test::MockSimpleDispatcher>(),
MOJO_HANDLE_RIGHT_WRITE);
auto hp = ht.AddHandlePair(h1.Clone(), h2.Clone());
auto hv1 = hp.first;
auto hv2 = hp.second;
ASSERT_NE(hv1, MOJO_HANDLE_INVALID);
ASSERT_NE(hv2, MOJO_HANDLE_INVALID);
ASSERT_NE(hv1, hv2);
// Table should be full; adding |h3| should fail.
EXPECT_EQ(MOJO_HANDLE_INVALID, ht.AddHandle(h3.Clone()));
// Adding |h3| and |h4| as a pair should also fail.
auto hp2 = ht.AddHandlePair(h3.Clone(), h4.Clone());
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.first);
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.second);
// Remove |hv2|/|h2|.
Handle h;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv2, &h));
ASSERT_EQ(h2, h);
// Trying to add |h3| and |h4| as a pair should still fail.
hp2 = ht.AddHandlePair(h3.Clone(), h4.Clone());
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.first);
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.second);
// Remove |hv1|/|h1|.
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv1, &h));
ASSERT_EQ(h1, h);
// Add |h3| and |h4| as a pair should now succeed fail.
hp2 = ht.AddHandlePair(h3.Clone(), h4.Clone());
auto hv3 = hp2.first;
auto hv4 = hp2.second;
ASSERT_NE(hv3, MOJO_HANDLE_INVALID);
ASSERT_NE(hv4, MOJO_HANDLE_INVALID);
ASSERT_NE(hv3, hv4);
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv3, &h));
ASSERT_EQ(h3, h);
h.reset();
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(hv4, &h));
ASSERT_EQ(h4, h);
EXPECT_EQ(MOJO_RESULT_OK, h1.dispatcher->Close());
EXPECT_EQ(MOJO_RESULT_OK, h2.dispatcher->Close());
EXPECT_EQ(MOJO_RESULT_OK, h3.dispatcher->Close());
EXPECT_EQ(MOJO_RESULT_OK, h4.dispatcher->Close());
}
TEST(HandleTableTest, AddHandleVector) {
static constexpr size_t kNumHandles = 10u;
HandleTable ht(1000u);
HandleVector handles;
for (size_t i = 0u; i < kNumHandles; i++) {
handles.push_back(Handle(MakeRefCounted<test::MockSimpleDispatcher>(),
static_cast<MojoHandleRights>(i)));
ASSERT_TRUE(handles[i]) << i;
}
std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
HandleVector handles_copy = handles;
ASSERT_TRUE(ht.AddHandleVector(&handles_copy, handle_values.data()));
for (size_t i = 0u; i < kNumHandles; i++) {
ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
EXPECT_FALSE(handles_copy[i]) << i;
Handle h;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(handle_values[i], &h)) << i;
ASSERT_EQ(handles[i], h) << i;
EXPECT_EQ(MOJO_RESULT_OK, handles[i].dispatcher->Close()) << i;
}
}
TEST(HandleTableTest, AddHandleVectorTooMany) {
static constexpr size_t kHandleTableSize = 10u;
static constexpr size_t kNumHandles = kHandleTableSize + 1u;
HandleTable ht(kHandleTableSize);
HandleVector handles;
for (size_t i = 0u; i < kNumHandles; i++) {
handles.push_back(Handle(MakeRefCounted<test::MockSimpleDispatcher>(),
static_cast<MojoHandleRights>(i)));
ASSERT_TRUE(handles[i]) << i;
}
std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
HandleVector handles_copy = handles;
EXPECT_FALSE(ht.AddHandleVector(&handles_copy, handle_values.data()));
handles_copy.pop_back();
handle_values.pop_back();
ASSERT_TRUE(ht.AddHandleVector(&handles_copy, handle_values.data()));
for (size_t i = 0u; i < kNumHandles - 1u; i++) {
ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
EXPECT_FALSE(handles_copy[i]) << i;
Handle h;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveHandle(handle_values[i], &h)) << i;
ASSERT_EQ(handles[i], h) << i;
}
for (size_t i = 0u; i < kNumHandles; i++)
EXPECT_EQ(MOJO_RESULT_OK, handles[i].dispatcher->Close()) << i;
}
} // namespace
} // namespace system
} // namespace mojo