| // Copyright 2017 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <sstream> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| #include <libsmbclient.h> |
| |
| #include "smbprovider/constants.h" |
| #include "smbprovider/proto.h" |
| #include "smbprovider/proto_bindings/directory_entry.pb.h" |
| #include "smbprovider/smbprovider_helper.h" |
| #include "smbprovider/smbprovider_test_helper.h" |
| #include "smbprovider/temp_file_manager.h" |
| |
| namespace smbprovider { |
| |
| class SmbProviderHelperTest : public testing::Test { |
| public: |
| SmbProviderHelperTest() = default; |
| SmbProviderHelperTest(const SmbProviderHelperTest&) = delete; |
| SmbProviderHelperTest& operator=(const SmbProviderHelperTest&) = delete; |
| |
| protected: |
| TempFileManager temp_file_manager_; |
| }; |
| |
| // Tests that AppendPath properly appends with or without the trailing separator |
| // "/" on the base path. |
| TEST_F(SmbProviderHelperTest, AppendPath) { |
| EXPECT_EQ("smb://qnap/testshare/test", |
| AppendPath("smb://qnap/testshare", "/test")); |
| EXPECT_EQ("smb://qnap/testshare/test", |
| AppendPath("smb://qnap/testshare/", "/test")); |
| EXPECT_EQ("smb://qnap/testshare/test", |
| AppendPath("smb://qnap/testshare", "test")); |
| EXPECT_EQ("smb://qnap/testshare/test", |
| AppendPath("smb://qnap/testshare/", "test")); |
| EXPECT_EQ("smb://qnap/testshare", AppendPath("smb://qnap/testshare/", "/")); |
| EXPECT_EQ("smb://qnap/testshare", AppendPath("smb://qnap/testshare/", "")); |
| } |
| |
| // Should return true on "." and ".." entries. |
| TEST_F(SmbProviderHelperTest, IsSelfOrParentDir) { |
| EXPECT_TRUE(IsSelfOrParentDir(".")); |
| EXPECT_TRUE(IsSelfOrParentDir("..")); |
| EXPECT_FALSE(IsSelfOrParentDir("/")); |
| EXPECT_FALSE(IsSelfOrParentDir("test.jpg")); |
| } |
| |
| // Only SMBC_DIR and SMBC_FILE should return true. |
| TEST_F(SmbProviderHelperTest, IsFileOrDir) { |
| EXPECT_TRUE(IsFileOrDir(SMBC_DIR)); |
| EXPECT_TRUE(IsFileOrDir(SMBC_FILE)); |
| |
| EXPECT_FALSE(IsFileOrDir(SMBC_WORKGROUP)); |
| EXPECT_FALSE(IsFileOrDir(SMBC_SERVER)); |
| EXPECT_FALSE(IsFileOrDir(SMBC_FILE_SHARE)); |
| EXPECT_FALSE(IsFileOrDir(SMBC_PRINTER_SHARE)); |
| EXPECT_FALSE(IsFileOrDir(SMBC_COMMS_SHARE)); |
| EXPECT_FALSE(IsFileOrDir(SMBC_IPC_SHARE)); |
| EXPECT_FALSE(IsFileOrDir(SMBC_LINK)); |
| } |
| |
| // Only SMBC_FILE_SHARE should return true. |
| TEST_F(SmbProviderHelperTest, IsSmbShare) { |
| EXPECT_TRUE(IsSmbShare(SMBC_FILE_SHARE)); |
| |
| EXPECT_FALSE(IsSmbShare(SMBC_DIR)); |
| EXPECT_FALSE(IsSmbShare(SMBC_FILE)); |
| EXPECT_FALSE(IsSmbShare(SMBC_WORKGROUP)); |
| EXPECT_FALSE(IsSmbShare(SMBC_SERVER)); |
| EXPECT_FALSE(IsSmbShare(SMBC_PRINTER_SHARE)); |
| EXPECT_FALSE(IsSmbShare(SMBC_COMMS_SHARE)); |
| EXPECT_FALSE(IsSmbShare(SMBC_IPC_SHARE)); |
| EXPECT_FALSE(IsSmbShare(SMBC_LINK)); |
| } |
| |
| // Errors should be returned correctly. |
| TEST_F(SmbProviderHelperTest, GetErrorFromErrno) { |
| EXPECT_EQ(ERROR_ACCESS_DENIED, GetErrorFromErrno(EPERM)); |
| EXPECT_EQ(ERROR_ACCESS_DENIED, GetErrorFromErrno(EACCES)); |
| |
| EXPECT_EQ(ERROR_NOT_FOUND, GetErrorFromErrno(ENOENT)); |
| |
| EXPECT_EQ(ERROR_TOO_MANY_OPENED, GetErrorFromErrno(EMFILE)); |
| EXPECT_EQ(ERROR_TOO_MANY_OPENED, GetErrorFromErrno(ENFILE)); |
| |
| EXPECT_EQ(ERROR_NOT_A_DIRECTORY, GetErrorFromErrno(ENOTDIR)); |
| |
| EXPECT_EQ(ERROR_NOT_A_FILE, GetErrorFromErrno(EISDIR)); |
| |
| EXPECT_EQ(ERROR_NOT_EMPTY, GetErrorFromErrno(ENOTEMPTY)); |
| |
| EXPECT_EQ(ERROR_EXISTS, GetErrorFromErrno(EEXIST)); |
| |
| EXPECT_EQ(ERROR_INVALID_OPERATION, GetErrorFromErrno(EINVAL)); |
| |
| EXPECT_EQ(ERROR_SMB1_UNSUPPORTED, GetErrorFromErrno(ECONNABORTED)); |
| |
| EXPECT_EQ(ERROR_OPERATION_FAILED, GetErrorFromErrno(EBADF)); |
| EXPECT_EQ(ERROR_OPERATION_FAILED, GetErrorFromErrno(ENODEV)); |
| EXPECT_EQ(ERROR_OPERATION_FAILED, GetErrorFromErrno(ETIMEDOUT)); |
| |
| // Errors without an explicit mapping get mapped |
| // to ERROR_FAILED. |
| EXPECT_EQ(ERROR_FAILED, GetErrorFromErrno(ENOSPC)); |
| EXPECT_EQ(ERROR_FAILED, GetErrorFromErrno(ESPIPE)); |
| } |
| |
| // Errors should be returned correctly. |
| TEST_F(SmbProviderHelperTest, GetErrorFromErrnoForReadDir) { |
| EXPECT_EQ(ERROR_ACCESS_DENIED, GetErrorFromErrnoForReadDir(EPERM)); |
| EXPECT_EQ(ERROR_ACCESS_DENIED, GetErrorFromErrnoForReadDir(EACCES)); |
| |
| EXPECT_EQ(ERROR_NOT_FOUND, GetErrorFromErrnoForReadDir(ENOENT)); |
| // EINVAL is returned when Samba attempts to parse a hostname |
| // (eg. \\qnap\testshare). |
| EXPECT_EQ(ERROR_NOT_FOUND, GetErrorFromErrnoForReadDir(EINVAL)); |
| |
| EXPECT_EQ(ERROR_TOO_MANY_OPENED, GetErrorFromErrnoForReadDir(EMFILE)); |
| EXPECT_EQ(ERROR_TOO_MANY_OPENED, GetErrorFromErrnoForReadDir(ENFILE)); |
| |
| EXPECT_EQ(ERROR_NOT_A_DIRECTORY, GetErrorFromErrnoForReadDir(ENOTDIR)); |
| |
| EXPECT_EQ(ERROR_NOT_A_FILE, GetErrorFromErrnoForReadDir(EISDIR)); |
| |
| EXPECT_EQ(ERROR_NOT_EMPTY, GetErrorFromErrnoForReadDir(ENOTEMPTY)); |
| |
| EXPECT_EQ(ERROR_EXISTS, GetErrorFromErrnoForReadDir(EEXIST)); |
| |
| EXPECT_EQ(ERROR_SMB1_UNSUPPORTED, GetErrorFromErrnoForReadDir(ECONNABORTED)); |
| |
| EXPECT_EQ(ERROR_OPERATION_FAILED, GetErrorFromErrno(EBADF)); |
| EXPECT_EQ(ERROR_OPERATION_FAILED, GetErrorFromErrno(ENODEV)); |
| EXPECT_EQ(ERROR_OPERATION_FAILED, GetErrorFromErrno(ETIMEDOUT)); |
| |
| // Errors without an explicit mapping get mapped |
| // to ERROR_FAILED. |
| EXPECT_EQ(ERROR_FAILED, GetErrorFromErrnoForReadDir(ENOSPC)); |
| EXPECT_EQ(ERROR_FAILED, GetErrorFromErrnoForReadDir(ESPIPE)); |
| } |
| |
| // IsDirectory should only return true on directory stats. |
| TEST_F(SmbProviderHelperTest, IsDirectory) { |
| struct stat dir_info; |
| dir_info.st_mode = 16877; // Dir mode |
| struct stat file_info; |
| file_info.st_mode = 33188; // File mode |
| |
| EXPECT_TRUE(IsDirectory(dir_info)); |
| EXPECT_FALSE(IsDirectory(file_info)); |
| } |
| |
| // IsFile should only return true on File stats. |
| TEST_F(SmbProviderHelperTest, IsFile) { |
| struct stat dir_info; |
| dir_info.st_mode = 16877; // Dir mode |
| struct stat file_info; |
| file_info.st_mode = 33188; // File mode |
| |
| EXPECT_TRUE(IsFile(file_info)); |
| EXPECT_FALSE(IsFile(dir_info)); |
| } |
| |
| // IsValidOpenFileFlags should return true on valid flags. |
| TEST_F(SmbProviderHelperTest, IsValidOpenFileFlags) { |
| EXPECT_TRUE(IsValidOpenFileFlags(O_RDWR)); |
| EXPECT_TRUE(IsValidOpenFileFlags(O_RDONLY)); |
| EXPECT_TRUE(IsValidOpenFileFlags(O_WRONLY)); |
| EXPECT_FALSE(IsValidOpenFileFlags(O_CREAT)); |
| EXPECT_FALSE(IsValidOpenFileFlags(O_TRUNC)); |
| } |
| |
| TEST_F(SmbProviderHelperTest, ReadFromFDErrorOnInvalidFd) { |
| std::vector<uint8_t> buffer; |
| int32_t error; |
| |
| WriteFileOptionsProto proto = CreateWriteFileOptionsProto( |
| 0 /* mount_id */, 1 /* file_id */, 0 /* offset */, 0 /* length */); |
| |
| // Create a file descriptor that is invalid. |
| base::ScopedFD invalid_fd; |
| EXPECT_FALSE(invalid_fd.is_valid()); |
| |
| // Should return an error when passing in an invalid file descriptor. |
| EXPECT_FALSE(ReadFromFD(proto, invalid_fd, &error, &buffer)); |
| EXPECT_EQ(ERROR_DBUS_PARSE_FAILED, static_cast<ErrorType>(error)); |
| } |
| |
| TEST_F(SmbProviderHelperTest, ReadFromFDFailsWithLengthLargerThanData) { |
| const std::vector<uint8_t> data = {0, 1, 2, 3}; |
| |
| // Send in options with length larger than the data. |
| WriteFileOptionsProto proto = CreateWriteFileOptionsProto( |
| 0 /* mount_id */, 1 /* file_id */, 0 /* offset */, data.size() + 1); |
| int32_t error; |
| |
| // Ensure that the fd created is valid. |
| base::ScopedFD fd(temp_file_manager_.CreateTempFile(data).release()); |
| EXPECT_TRUE(fd.is_valid()); |
| |
| // Should fail since it can't read that much data. |
| std::vector<uint8_t> buffer; |
| EXPECT_FALSE(ReadFromFD(proto, fd, &error, &buffer)); |
| EXPECT_EQ(ERROR_IO, static_cast<ErrorType>(error)); |
| } |
| |
| TEST_F(SmbProviderHelperTest, ReadFromFDSucceedsWithLengthSmallerThanData) { |
| const std::vector<uint8_t> data = {0, 1, 2, 3}; |
| |
| // Send in options with length smaller than the data. |
| WriteFileOptionsProto proto = CreateWriteFileOptionsProto( |
| 0 /* mount_id */, 1 /* file_id */, 0 /* offset */, data.size() - 1); |
| int32_t error; |
| |
| // Ensure that the fd created is valid. |
| base::ScopedFD fd(temp_file_manager_.CreateTempFile(data).release()); |
| EXPECT_TRUE(fd.is_valid()); |
| |
| // Should be OK. |
| std::vector<uint8_t> buffer; |
| EXPECT_TRUE(ReadFromFD(proto, fd, &error, &buffer)); |
| |
| // Should be equal to the truncated data. |
| const std::vector<uint8_t> expected = {0, 1, 2}; |
| EXPECT_EQ(expected, buffer); |
| } |
| |
| TEST_F(SmbProviderHelperTest, ReadFromFDSucceedsWithExactSize) { |
| const std::vector<uint8_t> data = {0, 1, 2, 3}; |
| |
| // Send in options with length equal to the data. |
| WriteFileOptionsProto proto = CreateWriteFileOptionsProto( |
| 0 /* mount_id */, 1 /* file_id */, 0 /* offset */, data.size()); |
| int32_t error; |
| |
| // Ensure that the fd created is valid. |
| base::ScopedFD fd(temp_file_manager_.CreateTempFile(data).release()); |
| EXPECT_TRUE(fd.is_valid()); |
| |
| // Should be OK. |
| std::vector<uint8_t> buffer; |
| EXPECT_TRUE(ReadFromFD(proto, fd, &error, &buffer)); |
| EXPECT_EQ(data, buffer); |
| } |
| |
| // SplitPath correctly splits a relative path into a vector of its components. |
| TEST_F(SmbProviderHelperTest, SplitPathCorrectlySplitsPath) { |
| const std::string relative_path = "/testShare/dogs/lab.jpg"; |
| |
| PathParts parts = SplitPath(relative_path); |
| |
| EXPECT_EQ(4, parts.size()); |
| EXPECT_EQ("/", parts[0]); |
| EXPECT_EQ("testShare", parts[1]); |
| EXPECT_EQ("dogs", parts[2]); |
| EXPECT_EQ("lab.jpg", parts[3]); |
| } |
| |
| // SplitPath correctly splits a standalone leading slash and a standalone |
| // directory. |
| TEST_F(SmbProviderHelperTest, SplitPathCorrectlySplitsRoot) { |
| const std::string root_path = "/"; |
| |
| PathParts parts = SplitPath(root_path); |
| |
| EXPECT_EQ(1, parts.size()); |
| EXPECT_EQ("/", parts[0]); |
| } |
| |
| // SplitPath correctly splits a standalone directory. |
| TEST_F(SmbProviderHelperTest, SplitPathCorrectlySplitsDirPath) { |
| const std::string dir_path = "/foo"; |
| |
| PathParts parts = SplitPath(dir_path); |
| |
| EXPECT_EQ(2, parts.size()); |
| EXPECT_EQ("/", parts[0]); |
| EXPECT_EQ("foo", parts[1]); |
| } |
| |
| // RemoveUrlScheme correctly removes the SMB Url scheme from an SMB Url. |
| TEST_F(SmbProviderHelperTest, RemoveUrlSchemeCorrectlyRemovesUrl) { |
| EXPECT_EQ("/testShare/dogs", RemoveURLScheme("smb://testShare/dogs")); |
| } |
| |
| // GetFileName correctly returns root when passed "smb://". |
| TEST_F(SmbProviderHelperTest, GetFileNameReturnsRoot) { |
| const std::string full_path = "smb://"; |
| |
| EXPECT_EQ("/", GetFileName(full_path)); |
| } |
| |
| // GetFileName correctly returns the filename when passed "smb://foo". |
| TEST_F(SmbProviderHelperTest, GetFileNameReturnsFileNameOnSingleDepth) { |
| const std::string full_path = "smb://foo"; |
| |
| EXPECT_EQ("foo", GetFileName(full_path)); |
| } |
| |
| // GetFileName correctly returns the filename from an SMB Url. |
| TEST_F(SmbProviderHelperTest, GetFileNameReturnsFileName) { |
| const std::string full_path = "smb://testShare/dogs/lab.jpg"; |
| |
| EXPECT_EQ("lab.jpg", GetFileName(full_path)); |
| } |
| |
| // GetDirPath correctly returns root when passed "smb://". |
| TEST_F(SmbProviderHelperTest, GetDirPathReturnsRoot) { |
| const std::string full_path = "smb://"; |
| |
| EXPECT_EQ("/", GetDirPath(full_path)); |
| } |
| |
| // GetDirPath correctly returns the dirpath when passed "smb://foo". |
| TEST_F(SmbProviderHelperTest, GetDirPathReturnsRootOnSingleDepth) { |
| const std::string full_path = "smb://foo"; |
| |
| EXPECT_EQ("/", GetDirPath(full_path)); |
| } |
| |
| // GetDirPath correctly returns the dirpath from an SMB Url. |
| TEST_F(SmbProviderHelperTest, GetDirPathReturnsParent) { |
| const std::string full_path = "smb://testShare/dogs/lab.jpg"; |
| |
| EXPECT_EQ("/testShare/dogs", GetDirPath(full_path)); |
| } |
| |
| TEST_F(SmbProviderHelperTest, ShouldReportCreateDirError) { |
| EXPECT_FALSE( |
| ShouldReportCreateDirError(0 /* result */, false /* ignore_existing */)); |
| EXPECT_FALSE( |
| ShouldReportCreateDirError(0 /* result */, true /* ignore_existing */)); |
| EXPECT_FALSE(ShouldReportCreateDirError(EEXIST, true /* ignore_existing */)); |
| EXPECT_TRUE(ShouldReportCreateDirError(EEXIST, false /* ignore_existing */)); |
| EXPECT_TRUE(ShouldReportCreateDirError(EPERM, false /* ignore_existing */)); |
| EXPECT_TRUE(ShouldReportCreateDirError(EPERM, true /* ignore_existing */)); |
| } |
| |
| // GetOpenFilePermissions correctly returns permissions. |
| TEST_F(SmbProviderHelperTest, GetOpenFilePermissions) { |
| OpenFileOptionsProto open_file_proto_read = CreateOpenFileOptionsProto( |
| 3 /* mount_id */, "smb://testShare/dir1/pic.png", false /* writeable */); |
| EXPECT_EQ(O_RDONLY, GetOpenFilePermissions(open_file_proto_read)); |
| |
| OpenFileOptionsProto open_file_proto_read_write = CreateOpenFileOptionsProto( |
| 3 /* mount_id */, "smb://testShare/dir1/pic.png", true /* writeable */); |
| EXPECT_EQ(O_RDWR, GetOpenFilePermissions(open_file_proto_read_write)); |
| |
| TruncateOptionsProto truncate_proto_blank; |
| EXPECT_EQ(O_WRONLY, GetOpenFilePermissions(truncate_proto_blank)); |
| |
| CopyEntryOptionsProto copy_entry_proto_blank; |
| EXPECT_EQ(O_RDONLY, GetOpenFilePermissions(copy_entry_proto_blank)); |
| } |
| |
| TEST_F(SmbProviderHelperTest, GetOpenFilePermissionsBoolean) { |
| EXPECT_EQ(O_RDWR, GetOpenFilePermissions(true)); |
| |
| EXPECT_EQ(O_RDONLY, GetOpenFilePermissions(false)); |
| } |
| |
| namespace { |
| |
| std::string ToString(ErrorType error) { |
| std::ostringstream out; |
| out << error; |
| return out.str(); |
| } |
| |
| } // namespace |
| |
| TEST_F(SmbProviderHelperTest, ErrorTypeOutputOperator) { |
| EXPECT_EQ(ToString(ERROR_NONE), "ERROR_NONE"); |
| EXPECT_EQ(ToString(ERROR_OK), "ERROR_OK"); |
| EXPECT_EQ(ToString(ERROR_FAILED), "ERROR_FAILED"); |
| EXPECT_EQ(ToString(ERROR_IN_USE), "ERROR_IN_USE"); |
| EXPECT_EQ(ToString(ERROR_EXISTS), "ERROR_EXISTS"); |
| EXPECT_EQ(ToString(ERROR_NOT_FOUND), "ERROR_NOT_FOUND"); |
| EXPECT_EQ(ToString(ERROR_ACCESS_DENIED), "ERROR_ACCESS_DENIED"); |
| EXPECT_EQ(ToString(ERROR_TOO_MANY_OPENED), "ERROR_TOO_MANY_OPENED"); |
| EXPECT_EQ(ToString(ERROR_NO_MEMORY), "ERROR_NO_MEMORY"); |
| EXPECT_EQ(ToString(ERROR_NO_SPACE), "ERROR_NO_SPACE"); |
| EXPECT_EQ(ToString(ERROR_NOT_A_DIRECTORY), "ERROR_NOT_A_DIRECTORY"); |
| EXPECT_EQ(ToString(ERROR_INVALID_OPERATION), "ERROR_INVALID_OPERATION"); |
| EXPECT_EQ(ToString(ERROR_SECURITY), "ERROR_SECURITY"); |
| EXPECT_EQ(ToString(ERROR_ABORT), "ERROR_ABORT"); |
| EXPECT_EQ(ToString(ERROR_NOT_A_FILE), "ERROR_NOT_A_FILE"); |
| EXPECT_EQ(ToString(ERROR_NOT_EMPTY), "ERROR_NOT_EMPTY"); |
| EXPECT_EQ(ToString(ERROR_INVALID_URL), "ERROR_INVALID_URL"); |
| EXPECT_EQ(ToString(ERROR_IO), "ERROR_IO"); |
| EXPECT_EQ(ToString(ERROR_PROVIDER_ERROR_COUNT), "ERROR_PROVIDER_ERROR_COUNT"); |
| EXPECT_EQ(ToString(ERROR_DBUS_PARSE_FAILED), "ERROR_DBUS_PARSE_FAILED"); |
| EXPECT_EQ(ToString(ERROR_COPY_PENDING), "ERROR_COPY_PENDING"); |
| EXPECT_EQ(ToString(ERROR_COPY_FAILED), "ERROR_COPY_FAILED"); |
| EXPECT_EQ(ToString(ERROR_SMB1_UNSUPPORTED), "ERROR_SMB1_UNSUPPORTED"); |
| EXPECT_EQ(ToString(ERROR_OPERATION_PENDING), "ERROR_OPERATION_PENDING"); |
| EXPECT_EQ(ToString(ERROR_OPERATION_FAILED), "ERROR_OPERATION_FAILED"); |
| EXPECT_EQ(ToString(ErrorType(987654)), "ERROR_987654"); |
| } |
| |
| } // namespace smbprovider |