Port libminijail unit tests to C++.
That way they can be run on Android Platform Continuous Testing,
which requires gtest for parsing of test output.
Fix one issue in free_label_strings(), which was not setting
|labels->count| to 0. Also fix some nits in test files.
Bug: 30973585
Change-Id: I8bdb414329aab82e2180d412b9ecc128beab7227
diff --git a/libminijail_unittest.cpp b/libminijail_unittest.cpp
new file mode 100644
index 0000000..4e75bdc
--- /dev/null
+++ b/libminijail_unittest.cpp
@@ -0,0 +1,213 @@
+// libminijail_unittest.cpp
+// 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.
+//
+// Test platform independent logic of Minijail using gtest.
+
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <gtest/gtest.h>
+
+#include "libminijail.h"
+#include "libminijail-private.h"
+#include "util.h"
+
+/* Prototypes needed only by test. */
+void *consumebytes(size_t length, char **buf, size_t *buflength);
+char *consumestr(char **buf, size_t *buflength);
+
+/* Silence unused variable warnings. */
+TEST(silence, silence_unused) {
+ EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
+ EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
+ EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
+}
+
+TEST(consumebytes, zero) {
+ char buf[1024];
+ size_t len = sizeof(buf);
+ char *pos = &buf[0];
+ EXPECT_TRUE(NULL != consumebytes(0, &pos, &len));
+ EXPECT_EQ(&buf[0], pos);
+ EXPECT_EQ(sizeof(buf), len);
+}
+
+TEST(consumebytes, exact) {
+ char buf[1024];
+ size_t len = sizeof(buf);
+ char *pos = &buf[0];
+ /* One past the end since it consumes the whole buffer. */
+ char *end = &buf[sizeof(buf)];
+ EXPECT_TRUE(NULL != consumebytes(len, &pos, &len));
+ EXPECT_EQ((size_t)0, len);
+ EXPECT_EQ(end, pos);
+}
+
+TEST(consumebytes, half) {
+ char buf[1024];
+ size_t len = sizeof(buf);
+ char *pos = &buf[0];
+ /* One past the end since it consumes the whole buffer. */
+ char *end = &buf[sizeof(buf) / 2];
+ EXPECT_TRUE(NULL != consumebytes(len / 2, &pos, &len));
+ EXPECT_EQ(sizeof(buf) / 2, len);
+ EXPECT_EQ(end, pos);
+}
+
+TEST(consumebytes, toolong) {
+ char buf[1024];
+ size_t len = sizeof(buf);
+ char *pos = &buf[0];
+ /* One past the end since it consumes the whole buffer. */
+ EXPECT_TRUE(NULL == consumebytes(len + 1, &pos, &len));
+ EXPECT_EQ(sizeof(buf), len);
+ EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr, zero) {
+ char buf[1024];
+ size_t len = 0;
+ char *pos = &buf[0];
+ memset(buf, 0xff, sizeof(buf));
+ EXPECT_EQ(NULL, consumestr(&pos, &len));
+ EXPECT_EQ((size_t)0, len);
+ EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr, nonul) {
+ char buf[1024];
+ size_t len = sizeof(buf);
+ char *pos = &buf[0];
+ memset(buf, 0xff, sizeof(buf));
+ EXPECT_EQ(NULL, consumestr(&pos, &len));
+ EXPECT_EQ(sizeof(buf), len);
+ EXPECT_EQ(&buf[0], pos);
+}
+
+TEST(consumestr, full) {
+ char buf[1024];
+ size_t len = sizeof(buf);
+ char *pos = &buf[0];
+ memset(buf, 0xff, sizeof(buf));
+ buf[sizeof(buf)-1] = '\0';
+ EXPECT_EQ((void *)buf, consumestr(&pos, &len));
+ EXPECT_EQ((size_t)0, len);
+ EXPECT_EQ(&buf[sizeof(buf)], pos);
+}
+
+TEST(consumestr, trailing_nul) {
+ char buf[1024];
+ size_t len = sizeof(buf) - 1;
+ char *pos = &buf[0];
+ memset(buf, 0xff, sizeof(buf));
+ buf[sizeof(buf)-1] = '\0';
+ EXPECT_EQ(NULL, consumestr(&pos, &len));
+ EXPECT_EQ(sizeof(buf) - 1, len);
+ EXPECT_EQ(&buf[0], pos);
+}
+
+class MarshalTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ m_ = minijail_new();
+ j_ = minijail_new();
+ size_ = minijail_size(m_);
+ }
+ virtual void TearDown() {
+ minijail_destroy(m_);
+ minijail_destroy(j_);
+ }
+
+ char buf_[4096];
+ struct minijail *m_;
+ struct minijail *j_;
+ size_t size_;
+};
+
+TEST_F(MarshalTest, empty) {
+ ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
+ EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
+}
+
+TEST_F(MarshalTest, 0xff) {
+ memset(buf_, 0xff, sizeof(buf_));
+ /* Should fail on the first consumestr since a NUL will never be found. */
+ EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
+}
+
+TEST(Test, minijail_run_pid_pipes_no_preload) {
+ pid_t pid;
+ int child_stdin, child_stdout, child_stderr;
+ int mj_run_ret;
+ ssize_t write_ret, read_ret;
+ const size_t buf_len = 128;
+ char buf[buf_len];
+ int status;
+#if defined(__ANDROID__)
+ char filename[] = "/system/bin/cat";
+#else
+ char filename[] = "/bin/cat";
+#endif
+ char teststr[] = "test\n";
+ size_t teststr_len = strlen(teststr);
+ char *argv[4];
+
+ struct minijail *j = minijail_new();
+
+ argv[0] = filename;
+ argv[1] = NULL;
+ mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv,
+ &pid,
+ &child_stdin, &child_stdout,
+ NULL);
+ EXPECT_EQ(mj_run_ret, 0);
+
+ write_ret = write(child_stdin, teststr, teststr_len);
+ EXPECT_EQ(write_ret, (int)teststr_len);
+
+ read_ret = read(child_stdout, buf, 8);
+ EXPECT_EQ(read_ret, (int)teststr_len);
+ buf[teststr_len] = 0;
+ EXPECT_EQ(strcmp(buf, teststr), 0);
+
+ EXPECT_EQ(kill(pid, SIGTERM), 0);
+ waitpid(pid, &status, 0);
+ ASSERT_TRUE(WIFSIGNALED(status));
+ EXPECT_EQ(WTERMSIG(status), SIGTERM);
+
+#if defined(__ANDROID__)
+ argv[0] = "/system/bin/sh";
+#else
+ argv[0] = "/bin/sh";
+#endif
+ argv[1] = "-c";
+ argv[2] = "echo test >&2";
+ argv[3] = NULL;
+ mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid,
+ &child_stdin, &child_stdout,
+ &child_stderr);
+ EXPECT_EQ(mj_run_ret, 0);
+
+ read_ret = read(child_stderr, buf, buf_len);
+ EXPECT_GE(read_ret, (int)teststr_len);
+
+ waitpid(pid, &status, 0);
+ ASSERT_TRUE(WIFEXITED(status));
+ EXPECT_EQ(WEXITSTATUS(status), 0);
+
+ minijail_destroy(j);
+}