blob: 55af970f05dbb4133c710672d4cb6c47893cf1fe [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);
RefPtr<Dispatcher> d = MakeRefCounted<test::MockSimpleDispatcher>();
MojoHandle hv = ht.AddHandle(Handle(d.Clone(), MOJO_HANDLE_RIGHT_NONE));
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 = d.get();
// Reset this, to make sure that the handle table takes a ref.
d = nullptr;
Handle h;
EXPECT_EQ(MOJO_RESULT_OK, ht.GetHandle(hv, &h));
EXPECT_EQ(dv, h.dispatcher.get());
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(hv, &d));
ASSERT_EQ(dv, d.get());
EXPECT_EQ(MOJO_RESULT_OK, d->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);
auto d1 = MakeRefCounted<test::MockSimpleDispatcher>();
auto d2 = MakeRefCounted<test::MockSimpleDispatcher>();
auto hp = ht.AddHandlePair(Handle(d1.Clone(), MOJO_HANDLE_RIGHT_NONE),
Handle(d2.Clone(), MOJO_HANDLE_RIGHT_NONE));
ASSERT_NE(hp.first, MOJO_HANDLE_INVALID);
ASSERT_NE(hp.second, MOJO_HANDLE_INVALID);
ASSERT_NE(hp.first, hp.second);
RefPtr<Dispatcher> d;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(hp.first, &d));
ASSERT_EQ(d1, d);
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(hp.second, &d));
ASSERT_EQ(d2, d);
EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
}
TEST(HandleTableTest, AddHandleTooMany) {
HandleTable ht(2u);
auto d1 = MakeRefCounted<test::MockSimpleDispatcher>();
auto d2 = MakeRefCounted<test::MockSimpleDispatcher>();
auto d3 = MakeRefCounted<test::MockSimpleDispatcher>();
MojoHandle h1 = ht.AddHandle(Handle(d1.Clone(), MOJO_HANDLE_RIGHT_NONE));
ASSERT_NE(h1, MOJO_HANDLE_INVALID);
MojoHandle h2 = ht.AddHandle(Handle(d2.Clone(), MOJO_HANDLE_RIGHT_NONE));
ASSERT_NE(h2, MOJO_HANDLE_INVALID);
EXPECT_NE(h2, h1);
// Table should be full; adding |d3| should fail.
EXPECT_EQ(MOJO_HANDLE_INVALID,
ht.AddHandle(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE)));
// Remove |h2|/|d2|.
RefPtr<Dispatcher> d;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h2, &d));
ASSERT_EQ(d2, d);
// Now adding |d3| should succeed.
MojoHandle h3 = ht.AddHandle(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE));
ASSERT_NE(h3, MOJO_HANDLE_INVALID);
EXPECT_NE(h3, h1);
// Note: |h3| may be equal to |h2| (handle values may be reused).
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h1, &d));
ASSERT_EQ(d1, d);
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h3, &d));
ASSERT_EQ(d3, d);
EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
EXPECT_EQ(MOJO_RESULT_OK, d3->Close());
}
TEST(HandleTableTest, AddHandlePairTooMany) {
HandleTable ht(2u);
auto d1 = MakeRefCounted<test::MockSimpleDispatcher>();
auto d2 = MakeRefCounted<test::MockSimpleDispatcher>();
auto d3 = MakeRefCounted<test::MockSimpleDispatcher>();
auto d4 = MakeRefCounted<test::MockSimpleDispatcher>();
auto hp = ht.AddHandlePair(Handle(d1.Clone(), MOJO_HANDLE_RIGHT_NONE),
Handle(d2.Clone(), MOJO_HANDLE_RIGHT_NONE));
auto h1 = hp.first;
auto h2 = hp.second;
ASSERT_NE(h1, MOJO_HANDLE_INVALID);
ASSERT_NE(h2, MOJO_HANDLE_INVALID);
ASSERT_NE(h1, h2);
// Table should be full; adding |d3| should fail.
EXPECT_EQ(MOJO_HANDLE_INVALID,
ht.AddHandle(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE)));
// Adding |d3| and |d4| as a pair should also fail.
auto hp2 = ht.AddHandlePair(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE),
Handle(d4.Clone(), MOJO_HANDLE_RIGHT_NONE));
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.first);
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.second);
// Remove |h2|/|d2|.
RefPtr<Dispatcher> d;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h2, &d));
ASSERT_EQ(d2, d);
// Trying to add |d3| and |d4| as a pair should still fail.
hp2 = ht.AddHandlePair(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE),
Handle(d4.Clone(), MOJO_HANDLE_RIGHT_NONE));
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.first);
EXPECT_EQ(MOJO_HANDLE_INVALID, hp2.second);
// Remove |h1|/|d1|.
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h1, &d));
ASSERT_EQ(d1, d);
// Add |d3| and |d4| as a pair should now succeed fail.
hp2 = ht.AddHandlePair(Handle(d3.Clone(), MOJO_HANDLE_RIGHT_NONE),
Handle(d4.Clone(), MOJO_HANDLE_RIGHT_NONE));
auto h3 = hp2.first;
auto h4 = hp2.second;
ASSERT_NE(h3, MOJO_HANDLE_INVALID);
ASSERT_NE(h4, MOJO_HANDLE_INVALID);
ASSERT_NE(h3, h4);
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h3, &d));
ASSERT_EQ(d3, d);
d = nullptr;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(h4, &d));
ASSERT_EQ(d4, d);
EXPECT_EQ(MOJO_RESULT_OK, d1->Close());
EXPECT_EQ(MOJO_RESULT_OK, d2->Close());
EXPECT_EQ(MOJO_RESULT_OK, d3->Close());
EXPECT_EQ(MOJO_RESULT_OK, d4->Close());
}
TEST(HandleTableTest, AddHandleVector) {
static constexpr size_t kNumHandles = 10u;
HandleTable ht(1000u);
HandleVector handles;
std::vector<RefPtr<Dispatcher>> dispatchers;
for (size_t i = 0u; i < kNumHandles; i++) {
dispatchers.push_back(MakeRefCounted<test::MockSimpleDispatcher>());
handles.push_back(
Handle(dispatchers.back().Clone(), MOJO_HANDLE_RIGHT_NONE));
ASSERT_TRUE(handles[i]) << i;
}
std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
ASSERT_TRUE(ht.AddHandleVector(&handles, handle_values.data()));
for (size_t i = 0u; i < kNumHandles; i++) {
ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
RefPtr<Dispatcher> d;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(handle_values[i], &d))
<< i;
ASSERT_EQ(dispatchers[i], d) << i;
EXPECT_EQ(MOJO_RESULT_OK, dispatchers[i]->Close()) << i;
}
}
TEST(HandleTableTest, AddHandleVectorTooMany) {
static constexpr size_t kHandleTableSize = 10u;
static constexpr size_t kNumHandles = kHandleTableSize + 1u;
HandleTable ht(kHandleTableSize);
HandleVector handles;
std::vector<RefPtr<Dispatcher>> dispatchers;
for (size_t i = 0u; i < kNumHandles; i++) {
dispatchers.push_back(MakeRefCounted<test::MockSimpleDispatcher>());
handles.push_back(
Handle(dispatchers.back().Clone(), MOJO_HANDLE_RIGHT_NONE));
ASSERT_TRUE(handles[i]) << i;
}
std::vector<MojoHandle> handle_values(kNumHandles, MOJO_HANDLE_INVALID);
EXPECT_FALSE(ht.AddHandleVector(&handles, handle_values.data()));
handles.pop_back();
handle_values.pop_back();
ASSERT_TRUE(ht.AddHandleVector(&handles, handle_values.data()));
for (size_t i = 0u; i < kNumHandles - 1u; i++) {
ASSERT_NE(handle_values[i], MOJO_HANDLE_INVALID) << i;
RefPtr<Dispatcher> d;
ASSERT_EQ(MOJO_RESULT_OK, ht.GetAndRemoveDispatcher(handle_values[i], &d))
<< i;
ASSERT_EQ(dispatchers[i], d) << i;
}
for (size_t i = 0u; i < kNumHandles; i++)
EXPECT_EQ(MOJO_RESULT_OK, dispatchers[i]->Close()) << i;
}
} // namespace
} // namespace system
} // namespace mojo