blob: b9922acb2bb49c33585a88fc9d4caff22d19a076 [file] [log] [blame]
// Copyright 2017 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/public/cpp/system/handle_signal_tracker.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/wait.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace {
class HandleSignalTrackerTest : public testing::Test {
public:
HandleSignalTrackerTest() {}
~HandleSignalTrackerTest() override {}
void WaitForNextNotification(HandleSignalTracker* tracker) {
base::RunLoop loop;
tracker->set_notification_callback(base::Bind(
[](base::RunLoop* loop, const HandleSignalsState& signals_state) {
loop->Quit();
},
&loop));
loop.Run();
tracker->set_notification_callback(
HandleSignalTracker::NotificationCallback());
}
private:
base::test::ScopedTaskEnvironment task_environment_;
DISALLOW_COPY_AND_ASSIGN(HandleSignalTrackerTest);
};
TEST_F(HandleSignalTrackerTest, StartsWithCorrectState) {
MessagePipe pipe;
{
HandleSignalTracker tracker(pipe.handle0.get(),
MOJO_HANDLE_SIGNAL_READABLE);
EXPECT_FALSE(tracker.last_known_state().readable());
}
WriteMessageRaw(pipe.handle1.get(), "hi", 2, nullptr, 0,
MOJO_WRITE_MESSAGE_FLAG_NONE);
Wait(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
MOJO_WATCH_CONDITION_SATISFIED);
{
HandleSignalTracker tracker(pipe.handle0.get(),
MOJO_HANDLE_SIGNAL_READABLE);
EXPECT_TRUE(tracker.last_known_state().readable());
}
}
TEST_F(HandleSignalTrackerTest, BasicTracking) {
MessagePipe pipe;
HandleSignalTracker tracker(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE);
EXPECT_FALSE(tracker.last_known_state().readable());
WriteMessageRaw(pipe.handle1.get(), "hi", 2, nullptr, 0,
MOJO_WRITE_MESSAGE_FLAG_NONE);
WaitForNextNotification(&tracker);
EXPECT_TRUE(tracker.last_known_state().readable());
std::vector<uint8_t> bytes;
ReadMessageRaw(pipe.handle0.get(), &bytes, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE);
WaitForNextNotification(&tracker);
EXPECT_FALSE(tracker.last_known_state().readable());
}
TEST_F(HandleSignalTrackerTest, DoesntUpdateOnIrrelevantChanges) {
MessagePipe pipe;
HandleSignalTracker readable_tracker(pipe.handle0.get(),
MOJO_HANDLE_SIGNAL_READABLE);
HandleSignalTracker peer_closed_tracker(pipe.handle0.get(),
MOJO_HANDLE_SIGNAL_PEER_CLOSED);
EXPECT_FALSE(readable_tracker.last_known_state().readable());
EXPECT_FALSE(peer_closed_tracker.last_known_state().peer_closed());
WriteMessageRaw(pipe.handle1.get(), "hi", 2, nullptr, 0,
MOJO_WRITE_MESSAGE_FLAG_NONE);
WaitForNextNotification(&readable_tracker);
EXPECT_TRUE(readable_tracker.last_known_state().readable());
EXPECT_FALSE(readable_tracker.last_known_state().peer_closed());
// Closing the peer won't change the |readable_tracker|'s state since there's
// still an unread message. Therefore the tracker's last known state should
// continue to reflect the state prior to peer closure even after the handle's
// signals state has updated.
pipe.handle1.reset();
WaitForNextNotification(&peer_closed_tracker);
EXPECT_TRUE(pipe.handle0->QuerySignalsState().peer_closed());
EXPECT_TRUE(peer_closed_tracker.last_known_state().peer_closed());
EXPECT_FALSE(readable_tracker.last_known_state().peer_closed());
// Now read the message, which will ultimately trigger the pipe becoming
// unreadable.
std::vector<uint8_t> bytes;
ReadMessageRaw(pipe.handle0.get(), &bytes, nullptr,
MOJO_READ_MESSAGE_FLAG_NONE);
WaitForNextNotification(&readable_tracker);
EXPECT_FALSE(readable_tracker.last_known_state().readable());
// And note that the |peer_closed_tracker| should not have seen the readable
// state change above since it's not relevant to its tracked signal.
EXPECT_TRUE(peer_closed_tracker.last_known_state().readable());
}
} // namespace
} // namespace mojo