| /* |
| * Copyright (C) 2017 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 <cstdint> |
| #include <memory> |
| |
| #include <gtest/gtest.h> |
| |
| #include "netdutils/Handle.h" |
| #include "netdutils/Math.h" |
| #include "netdutils/MockSyscalls.h" |
| #include "netdutils/Netfilter.h" |
| #include "netdutils/Netlink.h" |
| #include "netdutils/Slice.h" |
| #include "netdutils/Status.h" |
| #include "netdutils/StatusOr.h" |
| #include "netdutils/Syscalls.h" |
| |
| using testing::_; |
| using testing::ByMove; |
| using testing::Invoke; |
| using testing::Return; |
| using testing::StrictMock; |
| |
| namespace android { |
| namespace netdutils { |
| |
| class SyscallsTest : public testing::Test { |
| protected: |
| StrictMock<ScopedMockSyscalls> mSyscalls; |
| }; |
| |
| TEST(syscalls, scopedMock) { |
| auto& old = sSyscalls.get(); |
| { |
| StrictMock<ScopedMockSyscalls> s; |
| EXPECT_EQ(&s, &sSyscalls.get()); |
| } |
| EXPECT_EQ(&old, &sSyscalls.get()); |
| } |
| |
| TEST_F(SyscallsTest, open) { |
| const char kPath[] = "/test/path/please/ignore"; |
| constexpr Fd kFd(40); |
| constexpr int kFlags = 883; |
| constexpr mode_t kMode = 37373; |
| const auto& sys = sSyscalls.get(); |
| EXPECT_CALL(mSyscalls, open(kPath, kFlags, kMode)).WillOnce(Return(ByMove(UniqueFd(kFd)))); |
| EXPECT_CALL(mSyscalls, close(kFd)).WillOnce(Return(status::ok)); |
| auto result = sys.open(kPath, kFlags, kMode); |
| EXPECT_EQ(status::ok, result.status()); |
| EXPECT_EQ(kFd, result.value()); |
| } |
| |
| TEST_F(SyscallsTest, getsockname) { |
| constexpr Fd kFd(40); |
| sockaddr_nl expected = {}; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)) |
| .WillOnce(Invoke([expected](Fd, sockaddr* addr, socklen_t* addrlen) { |
| memcpy(addr, &expected, sizeof(expected)); |
| EXPECT_EQ(*addrlen, static_cast<socklen_t>(sizeof(expected))); |
| return status::ok; |
| })); |
| const auto result = sys.getsockname<sockaddr_nl>(kFd); |
| EXPECT_TRUE(isOk(result)); |
| EXPECT_EQ(expected, result.value()); |
| |
| // Failure |
| const Status kError = statusFromErrno(EINVAL, "test"); |
| EXPECT_CALL(mSyscalls, getsockname(kFd, _, _)).WillOnce(Return(kError)); |
| EXPECT_EQ(kError, sys.getsockname<sockaddr_nl>(kFd).status()); |
| } |
| |
| TEST_F(SyscallsTest, setsockopt) { |
| constexpr Fd kFd(40); |
| constexpr int kLevel = 50; |
| constexpr int kOptname = 70; |
| sockaddr_nl expected = {}; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected))) |
| .WillOnce(Return(status::ok)); |
| EXPECT_EQ(status::ok, sys.setsockopt(kFd, kLevel, kOptname, expected)); |
| |
| // Failure |
| const Status kError = statusFromErrno(EINVAL, "test"); |
| EXPECT_CALL(mSyscalls, setsockopt(kFd, kLevel, kOptname, &expected, sizeof(expected))) |
| .WillOnce(Return(kError)); |
| EXPECT_EQ(kError, sys.setsockopt(kFd, kLevel, kOptname, expected)); |
| } |
| |
| TEST_F(SyscallsTest, getsockopt) { |
| constexpr Fd kFd(40); |
| constexpr int kLevel = 50; |
| constexpr int kOptname = 70; |
| sockaddr_nl expected = {}; |
| socklen_t optLen = 0; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen)) |
| .WillOnce(Return(status::ok)); |
| EXPECT_EQ(status::ok, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen)); |
| |
| // Failure |
| const Status kError = statusFromErrno(EINVAL, "test"); |
| EXPECT_CALL(mSyscalls, getsockopt(kFd, kLevel, kOptname, &expected, &optLen)) |
| .WillOnce(Return(kError)); |
| EXPECT_EQ(kError, sys.getsockopt(kFd, kLevel, kOptname, &expected, &optLen)); |
| } |
| |
| TEST_F(SyscallsTest, bind) { |
| constexpr Fd kFd(40); |
| sockaddr_nl expected = {}; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected))) |
| .WillOnce(Return(status::ok)); |
| EXPECT_EQ(status::ok, sys.bind(kFd, expected)); |
| |
| // Failure |
| const Status kError = statusFromErrno(EINVAL, "test"); |
| EXPECT_CALL(mSyscalls, bind(kFd, asSockaddrPtr(&expected), sizeof(expected))) |
| .WillOnce(Return(kError)); |
| EXPECT_EQ(kError, sys.bind(kFd, expected)); |
| } |
| |
| TEST_F(SyscallsTest, connect) { |
| constexpr Fd kFd(40); |
| sockaddr_nl expected = {}; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected))) |
| .WillOnce(Return(status::ok)); |
| EXPECT_EQ(status::ok, sys.connect(kFd, expected)); |
| |
| // Failure |
| const Status kError = statusFromErrno(EINVAL, "test"); |
| EXPECT_CALL(mSyscalls, connect(kFd, asSockaddrPtr(&expected), sizeof(expected))) |
| .WillOnce(Return(kError)); |
| EXPECT_EQ(kError, sys.connect(kFd, expected)); |
| } |
| |
| TEST_F(SyscallsTest, sendto) { |
| constexpr Fd kFd(40); |
| constexpr int kFlags = 0; |
| std::array<char, 10> payload; |
| const auto slice = makeSlice(payload); |
| sockaddr_nl expected = {}; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, sendto(kFd, slice, kFlags, asSockaddrPtr(&expected), sizeof(expected))) |
| .WillOnce(Return(slice.size())); |
| EXPECT_EQ(status::ok, sys.sendto(kFd, slice, kFlags, expected)); |
| } |
| |
| TEST_F(SyscallsTest, recvfrom) { |
| constexpr Fd kFd(40); |
| constexpr int kFlags = 0; |
| std::array<char, 10> payload; |
| const auto dst = makeSlice(payload); |
| const auto used = take(dst, 8); |
| sockaddr_nl expected = {}; |
| auto& sys = sSyscalls.get(); |
| |
| // Success |
| EXPECT_CALL(mSyscalls, recvfrom(kFd, dst, kFlags, _, _)) |
| .WillOnce(Invoke( |
| [expected, used](Fd, const Slice, int, sockaddr* src, socklen_t* srclen) { |
| *srclen = sizeof(expected); |
| memcpy(src, &expected, *srclen); |
| return used; |
| })); |
| auto result = sys.recvfrom<sockaddr_nl>(kFd, dst, kFlags); |
| EXPECT_EQ(status::ok, result.status()); |
| EXPECT_EQ(used, result.value().first); |
| EXPECT_EQ(expected, result.value().second); |
| } |
| |
| } // namespace netdutils |
| } // namespace android |