blob: 175d69cad1a7776c6941a041aca0e545d94d1115 [file] [log] [blame]
// Copyright (c) 2010 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 "base/ref_counted.h"
#include "base/waitable_event.h"
#include "media/base/data_buffer.h"
#include "remoting/jingle_glue/jingle_channel.h"
#include "remoting/jingle_glue/jingle_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libjingle/source/talk/base/stream.h"
using testing::_;
using testing::Return;
using testing::Mock;
using testing::SetArgumentPointee;
namespace remoting {
namespace {
// Size of test buffer in bytes.
const size_t kBufferSize = 100;
} // namespace
class MockJingleChannelCallback : public JingleChannel::Callback {
public:
MOCK_METHOD2(OnStateChange, void(JingleChannel*, JingleChannel::State));
MOCK_METHOD2(OnPacketReceived, void(JingleChannel*,
scoped_refptr<media::DataBuffer>));
};
class MockStream : public talk_base::StreamInterface {
public:
virtual ~MockStream() {}
MOCK_CONST_METHOD0(GetState, talk_base::StreamState());
MOCK_METHOD4(Read, talk_base::StreamResult(void*, size_t, size_t*, int*));
MOCK_METHOD4(Write, talk_base::StreamResult(const void*, size_t,
size_t*, int*));
MOCK_CONST_METHOD1(GetAvailable, bool(size_t*));
MOCK_METHOD0(Close, void());
MOCK_METHOD3(PostEvent, void(talk_base::Thread*, int, int));
MOCK_METHOD2(PostEvent, void(int, int));
};
class JingleChannelTest : public testing::Test {
public:
virtual ~JingleChannelTest() { }
// A helper that calls OnStreamEvent(). Need this because we want
// to call it on the jingle thread.
static void StreamEvent(JingleChannel* channel,
talk_base::StreamInterface* stream,
int event, int error,
base::WaitableEvent* done_event) {
channel->OnStreamEvent(stream, event, error);
if (done_event)
done_event->Signal();
}
static void OnClosed(bool* called) {
*called = true;
}
protected:
virtual void SetUp() {
stream_ = new MockStream(); // Freed by the channel.
channel_ = new JingleChannel(&callback_);
channel_->thread_ = &thread_;
channel_->stream_.reset(stream_);
}
JingleThread thread_;
MockStream* stream_;
MockJingleChannelCallback callback_;
scoped_refptr<JingleChannel> channel_;
};
TEST_F(JingleChannelTest, Init) {
EXPECT_CALL(*stream_, GetState())
.Times(1)
.WillRepeatedly(Return(talk_base::SS_OPENING));
EXPECT_CALL(callback_, OnStateChange(channel_.get(),
JingleChannel::CONNECTING))
.Times(1);
thread_.Start();
EXPECT_EQ(JingleChannel::INITIALIZING, channel_->state());
channel_->Init(&thread_, stream_, "user@domain.com");
EXPECT_EQ(JingleChannel::CONNECTING, channel_->state());
channel_->closed_ = true;
thread_.Stop();
}
TEST_F(JingleChannelTest, Write) {
scoped_refptr<media::DataBuffer> data = new media::DataBuffer(kBufferSize);
data->SetDataSize(kBufferSize);
EXPECT_CALL(*stream_, Write(static_cast<const void*>(data->GetData()),
kBufferSize, _, _))
.WillOnce(DoAll(SetArgumentPointee<2>(kBufferSize),
Return(talk_base::SR_SUCCESS)));
channel_->state_ = JingleChannel::OPEN;
thread_.Start();
channel_->Write(data);
thread_.Stop();
channel_->closed_ = true;
}
TEST_F(JingleChannelTest, Read) {
scoped_refptr<media::DataBuffer> data = new media::DataBuffer(kBufferSize);
data->SetDataSize(kBufferSize);
EXPECT_CALL(callback_, OnPacketReceived(channel_.get(), _))
.Times(1);
EXPECT_CALL(*stream_, GetAvailable(_))
.WillOnce(DoAll(SetArgumentPointee<0>(kBufferSize),
Return(true)))
.WillOnce(DoAll(SetArgumentPointee<0>(0),
Return(true)));
EXPECT_CALL(*stream_, Read(_, kBufferSize, _, _))
.WillOnce(DoAll(SetArgumentPointee<2>(kBufferSize),
Return(talk_base::SR_SUCCESS)));
channel_->state_ = JingleChannel::OPEN;
thread_.Start();
base::WaitableEvent done_event(true, false);
thread_.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
&JingleChannelTest::StreamEvent, channel_.get(), stream_,
talk_base::SE_READ, 0, &done_event));
done_event.Wait();
thread_.Stop();
channel_->closed_ = true;
}
TEST_F(JingleChannelTest, Close) {
EXPECT_CALL(*stream_, Close()).Times(1);
// Don't expect any calls except Close().
EXPECT_CALL(*stream_, GetAvailable(_)).Times(0);
EXPECT_CALL(*stream_, Read(_, _, _, _)).Times(0);
EXPECT_CALL(callback_, OnPacketReceived(_, _)).Times(0);
thread_.Start();
channel_->Close();
// Verify that the channel doesn't call callback anymore.
thread_.message_loop()->PostTask(FROM_HERE, NewRunnableFunction(
&JingleChannelTest::StreamEvent, channel_.get(), stream_,
talk_base::SE_READ, 0, static_cast<base::WaitableEvent*>(NULL)));
thread_.Stop();
}
TEST_F(JingleChannelTest, ClosedTask) {
EXPECT_CALL(*stream_, Close())
.Times(1);
thread_.Start();
bool closed = false;
channel_->Close(NewRunnableFunction(&JingleChannelTest::OnClosed,
&closed));
thread_.Stop();
EXPECT_TRUE(closed);
}
TEST_F(JingleChannelTest, DoubleClose) {
EXPECT_CALL(*stream_, Close())
.Times(1);
thread_.Start();
bool closed1 = false;
channel_->Close(NewRunnableFunction(&JingleChannelTest::OnClosed,
&closed1));
bool closed2 = false;
channel_->Close(NewRunnableFunction(&JingleChannelTest::OnClosed,
&closed2));
thread_.Stop();
EXPECT_TRUE(closed1 && closed2);
}
} // namespace remoting