2 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "anbox/graphics/buffered_io_stream.h"
22 #include <gtest/gtest.h>
23 #include <gmock/gmock.h>
25 using namespace ::testing;
28 class MockSocketMessenger :
29 public anbox::network::SocketMessenger {
31 // anbox::network::SocketMessenger
32 MOCK_CONST_METHOD0(creds, anbox::network::Credentials());
33 MOCK_CONST_METHOD0(local_port, unsigned short());
34 MOCK_METHOD0(set_no_delay, void());
35 MOCK_METHOD0(close, void());
37 // anbox::network::MessageSender
38 MOCK_METHOD2(send, void(char const*, size_t));
39 MOCK_METHOD2(send_raw, ssize_t(char const*, size_t));
41 // anbox::network::MessageReceiver
42 MOCK_METHOD2(async_receive_msg, void(AnboxReadHandler const&, boost::asio::mutable_buffers_1 const&));
43 MOCK_METHOD1(receive_msg, boost::system::error_code(boost::asio::mutable_buffers_1 const&));
44 MOCK_METHOD0(available_bytes, size_t());
50 TEST(BufferedIOStream, CommitBufferWritesOutToMessenger) {
51 auto messenger = std::make_shared<MockSocketMessenger>();
52 BufferedIOStream stream(messenger);
54 const size_t buffer_size{1000};
55 // We will write out the data we get in two junks of half the size
56 // the original buffer has.
57 EXPECT_CALL(*messenger, send_raw(_, buffer_size))
59 .WillOnce(Return(buffer_size/2));
60 EXPECT_CALL(*messenger, send_raw(_, buffer_size/2))
62 .WillOnce(Return(buffer_size/2));
64 char *ptr = static_cast<char*>(stream.allocBuffer(buffer_size));
65 ASSERT_NE(ptr, nullptr);
66 ASSERT_EQ(stream.commitBuffer(buffer_size), buffer_size);
68 // The BufferedIOStream class works internally with a thread to
69 // write out the actual data to the messenger. As it blocks in
70 // its d'tor for the writer thread to quit we can safely expect
71 // that the messenger will see all data it has to.
74 TEST(BufferedIOStream, WriterContinuesWhenSocketIsBusy) {
75 auto messenger = std::make_shared<MockSocketMessenger>();
76 BufferedIOStream stream(messenger);
78 const size_t buffer_size{1000};
79 const size_t first_chunk_size{100};
80 // The writer will check the error code of the send function
81 // and will retry writing the next chunk when it doesn't get
82 // EAGAIN anymore from the sender.
83 EXPECT_CALL(*messenger, send_raw(_, buffer_size))
85 .WillOnce(Return(first_chunk_size));
86 EXPECT_CALL(*messenger, send_raw(_, buffer_size - first_chunk_size))
88 .WillOnce(DoAll(Invoke([](char const*, size_t) { errno = EAGAIN; }), Return(-EAGAIN)))
89 .WillOnce(Return(buffer_size - first_chunk_size));
91 char *ptr = static_cast<char*>(stream.allocBuffer(buffer_size));
92 ASSERT_NE(ptr, nullptr);
93 ASSERT_EQ(stream.commitBuffer(buffer_size), buffer_size);
96 TEST(BufferedIOStream, ReadWhenEnoughDataAvailable) {
97 auto messenger = std::make_shared<MockSocketMessenger>();
98 BufferedIOStream stream(messenger);
101 buffer.push_back(0x12);
102 buffer.push_back(0x34);
103 stream.post_data(std::move(buffer));
105 std::uint8_t read_data[1] = {0x0};
107 EXPECT_NE(nullptr, stream.read(read_data, &size));
109 EXPECT_EQ(0x12, read_data[0]);
111 EXPECT_NE(nullptr, stream.read(read_data, &size));
113 EXPECT_EQ(0x34, read_data[0]);
116 TEST(BufferedIOStream, ReadWithNoDataAvailable) {
117 auto messenger = std::make_shared<MockSocketMessenger>();
118 BufferedIOStream stream(messenger);
120 bool stopped = false;
121 std::thread producer([&](){
123 if (stream.needs_data()) {
125 buffer.push_back(0x12);
126 buffer.push_back(0x34);
127 stream.post_data(std::move(buffer));
129 std::this_thread::sleep_for(std::chrono::milliseconds{10});
133 constexpr size_t size{10};
134 std::uint8_t read_data[size] = {0x0};
136 EXPECT_NE(nullptr, stream.read(read_data, &read));
138 EXPECT_EQ(0x12, read_data[0]);
139 EXPECT_EQ(0x34, read_data[1]);
144 } // namespace graphics