blob: 02fec70aa83335df004907b7716e6eae6e56b193 [file] [log] [blame]
// 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 <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <vector>
#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