// Copyright 2015 The Bazel Authors. All rights reserved. // // 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 #include #include #include #include #include #include "src/main/cpp/blaze_util.h" #include "src/main/cpp/util/file.h" #include "gtest/gtest.h" namespace blaze { static bool Symlink(const string& old_path, const string& new_path) { return symlink(old_path.c_str(), new_path.c_str()) == 0; } static bool CreateEmptyFile(const string& path) { int fd = open(path.c_str(), O_CREAT | O_WRONLY); if (fd == -1) { return false; } return close(fd) == 0; } class BlazeUtilTest : public ::testing::Test { protected: BlazeUtilTest() { } virtual ~BlazeUtilTest() { } static void ForkAndWrite(int fds[], string input1, string input2) { int r = fork(); if (r == 0) { close(fds[0]); write(fds[1], input1.c_str(), input1.size()); usleep(500); // sleep for 50ms write(fds[1], input2.c_str(), input2.size()); close(fds[1]); exit(0); } else if (r < 0) { perror("fork()"); FAIL(); } else { close(fds[1]); } } static int WriteFileDescriptor2(string input1, string input2) { // create a fd for the input string int fds[2]; if (pipe(fds) == -1) { return -1; } if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1) { return -1; } if (input2.size() > 0) { ForkAndWrite(fds, input1, input2); } else { write(fds[1], input1.c_str(), input1.size()); close(fds[1]); } return fds[0]; } static void AssertReadFileDescriptor2(string input1, string input2) { int fd = WriteFileDescriptor2(input1, input2); if (fd < 0) { FAIL() << "Unable to create a pipe!"; } else { string result; if (!ReadFileDescriptor(fd, &result)) { perror("ReadFileDescriptor"); FAIL() << "Unable to read file descriptor!"; } else { ASSERT_EQ(input1 + input2, result); } } } static void AssertReadFileDescriptor(string input) { AssertReadFileDescriptor2(input, ""); } static void AssertReadJvmVersion2(string expected, string input1, string input2) { int fd = WriteFileDescriptor2(input1, input2); if (fd < 0) { FAIL() << "Unable to create a pipe!"; } else { ASSERT_EQ(expected, ReadJvmVersion(fd)); } } static void AssertReadJvmVersion(string expected, string input) { AssertReadJvmVersion2(expected, input, ""); } void ReadFileDescriptorTest() const { AssertReadFileDescriptor("DummyJDK Blabla\n" "More DummyJDK Blabla\n"); AssertReadFileDescriptor("dummyjdk version \"1.42.qual\"\n" "DummyJDK Blabla\n" "More DummyJDK Blabla\n"); AssertReadFileDescriptor2("first_line\n", "second line version \"1.4.2_0\"\n"); } void ReadJvmVersionTest() const { AssertReadJvmVersion("1.42", "dummyjdk version \"1.42\"\n" "DummyJDK Blabla\n" "More DummyJDK Blabla\n"); AssertReadJvmVersion("1.42.qual", "dummyjdk version \"1.42.qual\"\n" "DummyJDK Blabla\n" "More DummyJDK Blabla\n"); AssertReadJvmVersion("1.42.qualifie", "dummyjdk version \"1.42.qualifie"); AssertReadJvmVersion("", "dummyjdk version "); AssertReadJvmVersion2("1.4.2_0", "first_line\n", "second line version \"1.4.2_0\"\n"); } void CheckJavaVersionIsAtLeastTest() const { ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "0")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.7")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.7.0")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.0")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.6")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.42", "1")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.42", "1.7")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.42", "1.11")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.42.42", "1.11")); ASSERT_TRUE(CheckJavaVersionIsAtLeast("1.42.42", "1.11.11")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "42")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "2")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.8")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.7.1")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.7.0-ver-specifier-42", "1.42")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.42", "2")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.42", "1.69")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.42", "1.42.1")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.42.42", "1.42.43")); ASSERT_FALSE(CheckJavaVersionIsAtLeast("1.42.42.0", "1.42.42.1")); } }; TEST_F(BlazeUtilTest, CheckJavaVersionIsAtLeast) { CheckJavaVersionIsAtLeastTest(); } TEST_F(BlazeUtilTest, ReadFileDescriptor) { ReadFileDescriptorTest(); } TEST_F(BlazeUtilTest, ReadJvmVersion) { ReadJvmVersionTest(); } TEST_F(BlazeUtilTest, MakeDirectories) { const char* tmp_dir = getenv("TEST_TMPDIR"); ASSERT_STRNE(tmp_dir, NULL); const char* test_src_dir = getenv("TEST_SRCDIR"); ASSERT_STRNE(NULL, test_src_dir); string dir = blaze_util::JoinPath(tmp_dir, "x/y/z"); int ok = MakeDirectories(dir, 0755); ASSERT_EQ(0, ok); // Changing permissions on an existing dir should work. ok = MakeDirectories(dir, 0750); ASSERT_EQ(0, ok); struct stat filestat = {}; ASSERT_EQ(0, stat(dir.c_str(), &filestat)); ASSERT_EQ(0750, filestat.st_mode & 0777); // srcdir shouldn't be writable. // TODO(ulfjack): Fix this! // string srcdir = blaze_util::JoinPath(test_src_dir, "x/y/z"); // ok = MakeDirectories(srcdir, 0755); // ASSERT_EQ(-1, ok); // ASSERT_EQ(EACCES, errno); // Can't make a dir out of a file. string non_dir = blaze_util::JoinPath(dir, "w"); ASSERT_TRUE(CreateEmptyFile(non_dir)); ok = MakeDirectories(non_dir, 0755); ASSERT_EQ(-1, ok); ASSERT_EQ(ENOTDIR, errno); // Valid symlink should work. string symlink = blaze_util::JoinPath(tmp_dir, "z"); ASSERT_TRUE(Symlink(dir, symlink)); ok = MakeDirectories(symlink, 0755); ASSERT_EQ(0, ok); // Error: Symlink to a file. symlink = blaze_util::JoinPath(tmp_dir, "w"); ASSERT_TRUE(Symlink(non_dir, symlink)); ok = MakeDirectories(symlink, 0755); ASSERT_EQ(-1, ok); ASSERT_EQ(ENOTDIR, errno); // Error: Symlink to a dir with wrong perms. symlink = blaze_util::JoinPath(tmp_dir, "s"); ASSERT_TRUE(Symlink("/", symlink)); // These perms will force a chmod() // TODO(ulfjack): Fix this! // ok = MakeDirectories(symlink, 0000); // ASSERT_EQ(-1, ok); // ASSERT_EQ(EPERM, errno); // Edge cases. ASSERT_EQ(-1, MakeDirectories("", 0755)); ASSERT_EQ(EACCES, errno); ASSERT_EQ(-1, MakeDirectories("/", 0755)); ASSERT_EQ(EACCES, errno); } TEST_F(BlazeUtilTest, HammerMakeDirectories) { const char* tmp_dir = getenv("TEST_TMPDIR"); ASSERT_STRNE(tmp_dir, NULL); string path = blaze_util::JoinPath(tmp_dir, "x/y/z"); // TODO(ulfjack): Fix this! // ASSERT_LE(0, fork()); // ASSERT_EQ(0, MakeDirectories(path, 0755)); } } // namespace blaze