/* * 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