355 lines
12 KiB
C++
355 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2016, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <array>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <tuple>
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "wifilogd/local_utils.h"
|
|
#include "wifilogd/os.h"
|
|
#include "wifilogd/tests/mock_raw_os.h"
|
|
|
|
// This function must be defined in the same namespace as |timespec|. Hence the
|
|
// placement of this function at the top level.
|
|
inline void PrintTo(const timespec& ts, ::std::ostream* os) {
|
|
*os << "[secs:" << ts.tv_sec << " "
|
|
<< "nsecs:" << ts.tv_nsec << "]";
|
|
}
|
|
|
|
namespace android {
|
|
namespace wifilogd {
|
|
namespace {
|
|
|
|
using ::testing::_;
|
|
using ::testing::Invoke;
|
|
using ::testing::InSequence;
|
|
using ::testing::Matcher;
|
|
using ::testing::MatcherInterface;
|
|
using ::testing::MatchResultListener;
|
|
using ::testing::NotNull;
|
|
using ::testing::Pointee;
|
|
using ::testing::Return;
|
|
using ::testing::SetArgumentPointee;
|
|
using ::testing::SetErrnoAndReturn;
|
|
using ::testing::StrictMock;
|
|
using ::testing::StrEq;
|
|
|
|
using local_utils::GetMaxVal;
|
|
|
|
class OsTest : public ::testing::Test {
|
|
public:
|
|
OsTest() {
|
|
raw_os_ = new StrictMock<MockRawOs>();
|
|
os_ = std::unique_ptr<Os>(new Os(std::unique_ptr<RawOs>(raw_os_)));
|
|
}
|
|
|
|
protected:
|
|
std::unique_ptr<Os> os_;
|
|
// We use a raw pointer to access the mock, since ownership passes
|
|
// to |os_|.
|
|
MockRawOs* raw_os_;
|
|
};
|
|
|
|
class TimespecMatcher : public MatcherInterface<const timespec&> {
|
|
public:
|
|
explicit TimespecMatcher(const timespec& expected) : expected_(expected) {}
|
|
|
|
virtual void DescribeTo(::std::ostream* os) const {
|
|
*os << "equals ";
|
|
PrintTo(expected_, os);
|
|
}
|
|
|
|
virtual bool MatchAndExplain(const timespec& actual,
|
|
MatchResultListener* /* listener */) const {
|
|
return actual.tv_sec == expected_.tv_sec &&
|
|
actual.tv_nsec == expected_.tv_nsec;
|
|
}
|
|
|
|
private:
|
|
const timespec& expected_;
|
|
};
|
|
|
|
Matcher<const timespec&> EqualsTimespec(const timespec& expected) {
|
|
return MakeMatcher(new TimespecMatcher(expected));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
TEST_F(OsTest, GetControlSocketReturnsFdAndZeroOnSuccess) {
|
|
constexpr char kSocketName[] = "fake-daemon";
|
|
constexpr int kFakeValidFd = 100;
|
|
EXPECT_CALL(*raw_os_, GetControlSocket(StrEq(kSocketName)))
|
|
.WillOnce(Return(kFakeValidFd));
|
|
|
|
constexpr std::tuple<int, Os::Errno> kExpectedResult{kFakeValidFd, 0};
|
|
EXPECT_EQ(kExpectedResult, os_->GetControlSocket(kSocketName));
|
|
}
|
|
|
|
TEST_F(OsTest, GetControlSocketReturnsInvalidFdAndErrorOnFailure) {
|
|
constexpr char kSocketName[] = "fake-daemon";
|
|
constexpr Os::Errno kError = EINVAL;
|
|
EXPECT_CALL(*raw_os_, GetControlSocket(StrEq(kSocketName)))
|
|
.WillOnce(SetErrnoAndReturn(kError, -1));
|
|
|
|
constexpr std::tuple<int, Os::Errno> kExpectedResult{Os::kInvalidFd, kError};
|
|
EXPECT_EQ(kExpectedResult, os_->GetControlSocket(kSocketName));
|
|
}
|
|
|
|
TEST_F(OsTest, GetTimestampSucceeds) {
|
|
constexpr auto kFakeSecs = 1U;
|
|
constexpr auto kFakeNsecs = 2U;
|
|
constexpr struct timespec fake_time { kFakeSecs, kFakeNsecs };
|
|
EXPECT_CALL(*raw_os_, ClockGettime(_, _))
|
|
.WillOnce(DoAll(SetArgumentPointee<1>(fake_time), Return(0)));
|
|
|
|
const Os::Timestamp received = os_->GetTimestamp(CLOCK_REALTIME);
|
|
EXPECT_EQ(kFakeSecs, received.secs);
|
|
EXPECT_EQ(kFakeNsecs, received.nsecs);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepPassesNormalValueToSyscall) {
|
|
constexpr auto kSleepTimeNsec = 100;
|
|
EXPECT_CALL(*raw_os_,
|
|
Nanosleep(Pointee(EqualsTimespec({0, kSleepTimeNsec})), _));
|
|
os_->Nanosleep(kSleepTimeNsec);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepPassesMaxmimalValueToSyscall) {
|
|
EXPECT_CALL(*raw_os_,
|
|
Nanosleep(Pointee(EqualsTimespec({0, Os::kMaxNanos})), _));
|
|
os_->Nanosleep(Os::kMaxNanos);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepPassesZeroValueToSyscall) {
|
|
EXPECT_CALL(*raw_os_, Nanosleep(Pointee(EqualsTimespec({0, 0})), _));
|
|
os_->Nanosleep(0);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepClampsOverlyLargeValue) {
|
|
EXPECT_CALL(*raw_os_,
|
|
Nanosleep(Pointee(EqualsTimespec({0, Os::kMaxNanos})), _));
|
|
os_->Nanosleep(Os::kMaxNanos + 1);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepRetriesOnInterruptedCall) {
|
|
InSequence seq;
|
|
EXPECT_CALL(*raw_os_, Nanosleep(_, NotNull()))
|
|
.WillOnce(Invoke([](const timespec* /* desired */, timespec* remaining) {
|
|
*remaining = {0, 100};
|
|
errno = EINTR;
|
|
return -1;
|
|
}));
|
|
EXPECT_CALL(*raw_os_, Nanosleep(Pointee(EqualsTimespec({0, 100})), _));
|
|
os_->Nanosleep(Os::kMaxNanos);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepRetriesMultipleTimesIfNecessary) {
|
|
InSequence seq;
|
|
EXPECT_CALL(*raw_os_, Nanosleep(_, NotNull()))
|
|
.WillOnce(Invoke([](const timespec* /* desired */, timespec* remaining) {
|
|
*remaining = {0, 100};
|
|
errno = EINTR;
|
|
return -1;
|
|
}));
|
|
EXPECT_CALL(*raw_os_, Nanosleep(_, NotNull()))
|
|
.WillOnce(Invoke([](const timespec* /* desired */, timespec* remaining) {
|
|
*remaining = {0, 50};
|
|
errno = EINTR;
|
|
return -1;
|
|
}));
|
|
EXPECT_CALL(*raw_os_, Nanosleep(Pointee(EqualsTimespec({0, 50})), _));
|
|
os_->Nanosleep(Os::kMaxNanos);
|
|
}
|
|
|
|
TEST_F(OsTest, NanosleepIgnoresEintrWithZeroTimeRemaining) {
|
|
InSequence seq;
|
|
EXPECT_CALL(*raw_os_, Nanosleep(_, NotNull()))
|
|
.WillOnce(Invoke([](const timespec* /* desired */, timespec* remaining) {
|
|
*remaining = {0, 0};
|
|
errno = EINTR;
|
|
return -1;
|
|
}));
|
|
EXPECT_CALL(*raw_os_, Nanosleep(_, _)).Times(0);
|
|
os_->Nanosleep(Os::kMaxNanos);
|
|
}
|
|
|
|
TEST_F(OsTest, ReceiveDatagramReturnsCorrectValueForMaxSizedDatagram) {
|
|
constexpr int kFakeFd = 100;
|
|
std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_CALL(*raw_os_, Recv(kFakeFd, buffer.data(), buffer.size(), MSG_TRUNC))
|
|
.WillOnce(Return(buffer.size()));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{buffer.size(), 0};
|
|
EXPECT_EQ(kExpectedResult,
|
|
os_->ReceiveDatagram(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, ReceieveDatagramReturnsCorrectValueForRegularSizedDatagram) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr auto kReadBufferSize = 8192;
|
|
constexpr auto kDatagramSize = kReadBufferSize / 2;
|
|
std::array<uint8_t, kReadBufferSize> buffer{};
|
|
EXPECT_CALL(*raw_os_, Recv(kFakeFd, buffer.data(), buffer.size(), MSG_TRUNC))
|
|
.WillOnce(Return(kDatagramSize));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{kDatagramSize, 0};
|
|
EXPECT_EQ(kExpectedResult,
|
|
os_->ReceiveDatagram(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, ReceieveDatagramReturnsCorrectValueForOversizedDatagram) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr auto kReadBufferSize = 8192;
|
|
constexpr auto kDatagramSize = kReadBufferSize * 2;
|
|
std::array<uint8_t, kReadBufferSize> buffer{};
|
|
EXPECT_CALL(*raw_os_, Recv(kFakeFd, buffer.data(), buffer.size(), MSG_TRUNC))
|
|
.WillOnce(Return(kDatagramSize));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{kDatagramSize, 0};
|
|
EXPECT_EQ(kExpectedResult,
|
|
os_->ReceiveDatagram(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, ReceieveDatagramReturnsCorrectValueForZeroByteDatagram) {
|
|
constexpr int kFakeFd = 100;
|
|
std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_CALL(*raw_os_, Recv(kFakeFd, buffer.data(), buffer.size(), MSG_TRUNC))
|
|
.WillOnce(Return(0));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{0, 0};
|
|
EXPECT_EQ(kExpectedResult,
|
|
os_->ReceiveDatagram(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, ReceieveDatagramReturnsCorrectValueOnFailure) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr Os::Errno kError = EBADF;
|
|
std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_CALL(*raw_os_, Recv(kFakeFd, buffer.data(), buffer.size(), MSG_TRUNC))
|
|
.WillOnce(SetErrnoAndReturn(kError, -1));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{0, kError};
|
|
EXPECT_EQ(kExpectedResult,
|
|
os_->ReceiveDatagram(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, WriteReturnsCorrectValueForSuccessfulWrite) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_CALL(*raw_os_, Write(kFakeFd, buffer.data(), buffer.size()))
|
|
.WillOnce(Return(buffer.size()));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{buffer.size(), 0};
|
|
EXPECT_EQ(kExpectedResult, os_->Write(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, WriteReturnsCorrectValueForTruncatedWrite) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr int kBytesWritten = 4096;
|
|
constexpr std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_CALL(*raw_os_, Write(kFakeFd, buffer.data(), buffer.size()))
|
|
.WillOnce(Return(kBytesWritten));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{kBytesWritten, 0};
|
|
EXPECT_EQ(kExpectedResult, os_->Write(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, WriteReturnsCorrectValueForSuccessfulZeroByteWrite) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr std::array<uint8_t, 0> buffer{};
|
|
EXPECT_CALL(*raw_os_, Write(kFakeFd, buffer.data(), 0)).WillOnce(Return(0));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{0, 0};
|
|
EXPECT_EQ(kExpectedResult, os_->Write(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, WriteReturnsCorrectValueForFailedWrite) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr Os::Errno kError = EBADF;
|
|
constexpr std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_CALL(*raw_os_, Write(kFakeFd, buffer.data(), buffer.size()))
|
|
.WillOnce(SetErrnoAndReturn(kError, -1));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{0, kError};
|
|
EXPECT_EQ(kExpectedResult, os_->Write(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
TEST_F(OsTest, WriteReturnsCorrectValueForFailedZeroByteWrite) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr Os::Errno kError = EBADF;
|
|
constexpr std::array<uint8_t, 0> buffer{};
|
|
EXPECT_CALL(*raw_os_, Write(kFakeFd, buffer.data(), 0))
|
|
.WillOnce(SetErrnoAndReturn(kError, -1));
|
|
|
|
constexpr std::tuple<size_t, Os::Errno> kExpectedResult{0, kError};
|
|
EXPECT_EQ(kExpectedResult, os_->Write(kFakeFd, buffer.data(), buffer.size()));
|
|
}
|
|
|
|
// Per
|
|
// github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#death-tests,
|
|
// death tests should be specially named.
|
|
using OsDeathTest = OsTest;
|
|
|
|
TEST_F(OsDeathTest, GetTimestampOverlyLargeNsecsCausesDeath) {
|
|
constexpr auto kFakeSecs = 1U;
|
|
constexpr auto kFakeNsecs = 1000 * 1000 * 1000;
|
|
constexpr struct timespec fake_time { kFakeSecs, kFakeNsecs };
|
|
ON_CALL(*raw_os_, ClockGettime(_, _))
|
|
.WillByDefault(DoAll(SetArgumentPointee<1>(fake_time), Return(0)));
|
|
EXPECT_DEATH(os_->GetTimestamp(CLOCK_REALTIME), "Check failed");
|
|
}
|
|
|
|
TEST_F(OsDeathTest, GetTimestampRawOsErrorCausesDeath) {
|
|
ON_CALL(*raw_os_, ClockGettime(_, _)).WillByDefault(Return(-1));
|
|
EXPECT_DEATH(os_->GetTimestamp(CLOCK_REALTIME), "Unexpected error");
|
|
}
|
|
|
|
TEST_F(OsDeathTest, NanosleepUnexpectedErrorCausesDeath) {
|
|
ON_CALL(*raw_os_, Nanosleep(Pointee(EqualsTimespec({0, Os::kMaxNanos})), _))
|
|
.WillByDefault(SetErrnoAndReturn(EFAULT, -1));
|
|
EXPECT_DEATH(os_->Nanosleep(Os::kMaxNanos), "Unexpected error");
|
|
}
|
|
|
|
TEST_F(OsDeathTest, ReceiveDatagramWithOverlyLargeBufferCausesDeath) {
|
|
constexpr int kFakeFd = 100;
|
|
std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_DEATH(
|
|
os_->ReceiveDatagram(kFakeFd, buffer.data(), GetMaxVal<size_t>()),
|
|
"Check failed");
|
|
}
|
|
|
|
TEST_F(OsDeathTest, WriteWithOverlyLargeBufferCausesDeath) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr std::array<uint8_t, 8192> buffer{};
|
|
EXPECT_DEATH(os_->Write(kFakeFd, buffer.data(), GetMaxVal<size_t>()),
|
|
"Check failed");
|
|
}
|
|
|
|
TEST_F(OsDeathTest, WriteWithOverrunCausesDeath) {
|
|
constexpr int kFakeFd = 100;
|
|
constexpr std::array<uint8_t, 8192> buffer{};
|
|
ON_CALL(*raw_os_, Write(kFakeFd, buffer.data(), buffer.size()))
|
|
.WillByDefault(Return(buffer.size() + 1));
|
|
EXPECT_DEATH(os_->Write(kFakeFd, buffer.data(), buffer.size()),
|
|
"Check failed");
|
|
}
|
|
|
|
} // namespace wifilogd
|
|
} // namespace android
|