blob: 846f89d7ff706fbf8da7f6662c4267a2445bd7f5 [file] [log] [blame]
// Copyright 2018 The Android Open Source Project
//
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/emulation/CrossSessionSocket.h"
#include "android/base/files/InplaceStream.h"
#include "android/base/sockets/SocketUtils.h"
#include <cstring>
#include <gtest/gtest.h>
namespace android {
namespace emulation {
TEST(CrossSessionSocket, ReclaimWithoutRegister) {
CrossSessionSocket::clearRecycleSockets();
const int kUnknownFd = 1;
EXPECT_FALSE(CrossSessionSocket::reclaimSocket(kUnknownFd).valid());
}
TEST(CrossSessionSocket, Recycle) {
CrossSessionSocket::clearRecycleSockets();
int fd = base::socketCreateTcp4();
CrossSessionSocket socket(fd);
EXPECT_TRUE(socket.valid());
CrossSessionSocket::registerForRecycle(socket.fd());
CrossSessionSocket::recycleSocket(std::move(socket));
EXPECT_FALSE(socket.valid());
CrossSessionSocket recycled = CrossSessionSocket::reclaimSocket(fd);
EXPECT_TRUE(recycled.valid());
EXPECT_EQ(recycled.fd(), fd);
CrossSessionSocket::clearRecycleSockets();
}
TEST(CrossSessionSocket, ReclaimTwice) {
CrossSessionSocket::clearRecycleSockets();
int fd = base::socketCreateTcp4();
CrossSessionSocket socket(fd);
EXPECT_TRUE(socket.valid());
CrossSessionSocket::registerForRecycle(socket.fd());
CrossSessionSocket::recycleSocket(std::move(socket));
CrossSessionSocket::reclaimSocket(fd);
CrossSessionSocket recycled = CrossSessionSocket::reclaimSocket(fd);
EXPECT_FALSE(recycled.valid());
CrossSessionSocket::clearRecycleSockets();
}
TEST(CrossSessionSocket, RecycleWithoutRegister) {
CrossSessionSocket::clearRecycleSockets();
int fd = base::socketCreateTcp4();
CrossSessionSocket socket(fd);
EXPECT_TRUE(socket.valid());
CrossSessionSocket::recycleSocket(std::move(socket));
EXPECT_TRUE(socket.valid());
CrossSessionSocket recycled = CrossSessionSocket::reclaimSocket(fd);
EXPECT_FALSE(recycled.valid());
CrossSessionSocket::clearRecycleSockets();
}
TEST(CrossSessionSocket, DrainStale) {
const char* kContents = "Stale text";
const int kContentSize = strlen(kContents) + 1;
// Make buffer slightly larger so that it can catch if there are
// unexpected extra bits written to the buffer.
const int kBufferSize = kContentSize + 10;
// Number of bytes going to be written into the snapshot
const int kSnapshotSize = kBufferSize + 4;
CrossSessionSocket::clearRecycleSockets();
int fd1, fd2;
int ret = base::socketCreatePair(&fd1, &fd2);
EXPECT_EQ(0, ret);
CrossSessionSocket socket(fd1);
CrossSessionSocket::registerForRecycle(socket.fd());
ssize_t sendSize = base::socketSend(fd2, kContents, kContentSize);
EXPECT_EQ(kContentSize, sendSize);
socket.drainSocket(CrossSessionSocket::DrainBehavior::AppendToBuffer);
char snapshotBuffer[kSnapshotSize];
base::InplaceStream snapshotStream(snapshotBuffer, kSnapshotSize);
socket.onSave(&snapshotStream);
CrossSessionSocket::recycleSocket(std::move(socket));
CrossSessionSocket socket2 = CrossSessionSocket::reclaimSocket(fd1);
socket2.onLoad(&snapshotStream);
char readbackBuffer[kBufferSize];
ssize_t readSize = socket2.readStaleData(readbackBuffer, kBufferSize);
EXPECT_EQ(kContentSize, readSize);
EXPECT_EQ(0, memcmp(kContents, readbackBuffer, kContentSize));
// fd1 will be closed automatically
base::socketClose(fd2);
CrossSessionSocket::clearRecycleSockets();
}
} // namespace emulation
} // namespace android