Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6d37cdb authored by Tom Cherry's avatar Tom Cherry
Browse files

init: clean up subcontext_test

subcontext_test had been failing due to setexeccon() failing to
transition to vendor_init context.  This is a good thing as nothing
other than init should be able to transition into this context.

I don't want to add code to skip the setexeccon() call only for the
tests, so I instead call setexeccon() with the return value of
getcon().  This works however only for root, so these tests are
skipped for non-root.

Test: init unit tests
Change-Id: I8a415599e0ec5506511202f7f5018c0e5265837d
parent b3959bb4
Loading
Loading
Loading
Loading
+1 −16
Original line number Original line Diff line number Diff line
@@ -35,7 +35,7 @@ extern const std::string kVendorContext;
class Subcontext {
class Subcontext {
  public:
  public:
    Subcontext(std::string path_prefix, std::string context)
    Subcontext(std::string path_prefix, std::string context)
        : path_prefix_(std::move(path_prefix)), context_(std::move(context)) {
        : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) {
        Fork();
        Fork();
    }
    }


@@ -55,21 +55,6 @@ class Subcontext {
    android::base::unique_fd socket_;
    android::base::unique_fd socket_;
};
};


// For testing, to kill the subcontext after the test has completed.
class SubcontextKiller {
  public:
    SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {}
    ~SubcontextKiller() {
        if (subcontext_.pid() > 0) {
            kill(subcontext_.pid(), SIGTERM);
            kill(subcontext_.pid(), SIGKILL);
        }
    }

  private:
    const Subcontext& subcontext_;
};

int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map);
int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map);
std::vector<Subcontext>* InitializeSubcontexts();
std::vector<Subcontext>* InitializeSubcontexts();
bool SubcontextChildReap(pid_t pid);
bool SubcontextChildReap(pid_t pid);
+18 −2
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
#include "subcontext.h"
#include "subcontext.h"


#include <benchmark/benchmark.h>
#include <benchmark/benchmark.h>
#include <selinux/selinux.h>


#include "test_function_map.h"
#include "test_function_map.h"


@@ -24,12 +25,27 @@ namespace android {
namespace init {
namespace init {


static void BenchmarkSuccess(benchmark::State& state) {
static void BenchmarkSuccess(benchmark::State& state) {
    auto subcontext = Subcontext("path", kVendorContext);
    if (getuid() != 0) {
    auto subcontext_killer = SubcontextKiller(subcontext);
        state.SkipWithError("Skipping benchmark, must be run as root.");
        return;
    }
    char* context;
    if (getcon(&context) != 0) {
        state.SkipWithError("getcon() failed");
        return;
    }

    auto subcontext = Subcontext("path", context);
    free(context);


    while (state.KeepRunning()) {
    while (state.KeepRunning()) {
        subcontext.Execute(std::vector<std::string>{"return_success"});
        subcontext.Execute(std::vector<std::string>{"return_success"});
    }
    }

    if (subcontext.pid() > 0) {
        kill(subcontext.pid(), SIGTERM);
        kill(subcontext.pid(), SIGKILL);
    }
}
}


BENCHMARK(BenchmarkSuccess);
BENCHMARK(BenchmarkSuccess);
+82 −61
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include <android-base/properties.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/strings.h>
#include <gtest/gtest.h>
#include <gtest/gtest.h>
#include <selinux/selinux.h>


#include "builtin_arguments.h"
#include "builtin_arguments.h"
#include "test_function_map.h"
#include "test_function_map.h"
@@ -38,10 +39,33 @@ using android::base::WaitForProperty;
namespace android {
namespace android {
namespace init {
namespace init {


TEST(subcontext, CheckDifferentPid) {
// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have
    auto subcontext = Subcontext("path", kVendorContext);
// this test runner.
    auto subcontext_killer = SubcontextKiller(subcontext);
template <typename F>
void RunTest(F&& test_function) {
    if (getuid() != 0) {
        GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
        return;
    }

    char* context;
    ASSERT_EQ(0, getcon(&context));
    auto context_string = std::string(context);
    free(context);

    auto subcontext = Subcontext("dummy_path", context_string);
    ASSERT_NE(0, subcontext.pid());

    test_function(subcontext, context_string);


    if (subcontext.pid() > 0) {
        kill(subcontext.pid(), SIGTERM);
        kill(subcontext.pid(), SIGKILL);
    }
}

TEST(subcontext, CheckDifferentPid) {
    RunTest([](auto& subcontext, auto& context_string) {
        auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
        auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
        ASSERT_FALSE(result);
        ASSERT_FALSE(result);


@@ -50,12 +74,11 @@ TEST(subcontext, CheckDifferentPid) {
        auto our_pid = std::to_string(getpid());
        auto our_pid = std::to_string(getpid());
        EXPECT_NE(our_pid, pids[0]);
        EXPECT_NE(our_pid, pids[0]);
        EXPECT_EQ(our_pid, pids[1]);
        EXPECT_EQ(our_pid, pids[1]);
    });
}
}


TEST(subcontext, SetProp) {
TEST(subcontext, SetProp) {
    auto subcontext = Subcontext("path", kVendorContext);
    RunTest([](auto& subcontext, auto& context_string) {
    auto subcontext_killer = SubcontextKiller(subcontext);

        SetProperty("init.test.subcontext", "fail");
        SetProperty("init.test.subcontext", "fail");
        WaitForProperty("init.test.subcontext", "fail");
        WaitForProperty("init.test.subcontext", "fail");


@@ -68,12 +91,11 @@ TEST(subcontext, SetProp) {
        ASSERT_TRUE(result) << result.error();
        ASSERT_TRUE(result) << result.error();


        EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
        EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
    });
}
}


TEST(subcontext, MultipleCommands) {
TEST(subcontext, MultipleCommands) {
    auto subcontext = Subcontext("path", kVendorContext);
    RunTest([](auto& subcontext, auto& context_string) {
    auto subcontext_killer = SubcontextKiller(subcontext);

        auto first_pid = subcontext.pid();
        auto first_pid = subcontext.pid();


        auto expected_words = std::vector<std::string>{
        auto expected_words = std::vector<std::string>{
@@ -96,12 +118,11 @@ TEST(subcontext, MultipleCommands) {
        ASSERT_FALSE(result);
        ASSERT_FALSE(result);
        EXPECT_EQ(Join(expected_words, " "), result.error_string());
        EXPECT_EQ(Join(expected_words, " "), result.error_string());
        EXPECT_EQ(first_pid, subcontext.pid());
        EXPECT_EQ(first_pid, subcontext.pid());
    });
}
}


TEST(subcontext, RecoverAfterAbort) {
TEST(subcontext, RecoverAfterAbort) {
    auto subcontext = Subcontext("path", kVendorContext);
    RunTest([](auto& subcontext, auto& context_string) {
    auto subcontext_killer = SubcontextKiller(subcontext);

        auto first_pid = subcontext.pid();
        auto first_pid = subcontext.pid();


        auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
        auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
@@ -111,15 +132,15 @@ TEST(subcontext, RecoverAfterAbort) {
        ASSERT_FALSE(result2);
        ASSERT_FALSE(result2);
        EXPECT_EQ("Sane error!", result2.error_string());
        EXPECT_EQ("Sane error!", result2.error_string());
        EXPECT_NE(subcontext.pid(), first_pid);
        EXPECT_NE(subcontext.pid(), first_pid);
    });
}
}


TEST(subcontext, ContextString) {
TEST(subcontext, ContextString) {
    auto subcontext = Subcontext("path", kVendorContext);
    RunTest([](auto& subcontext, auto& context_string) {
    auto subcontext_killer = SubcontextKiller(subcontext);

        auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
        auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
        ASSERT_FALSE(result);
        ASSERT_FALSE(result);
    ASSERT_EQ(kVendorContext, result.error_string());
        ASSERT_EQ(context_string, result.error_string());
    });
}
}


TestFunctionMap BuildTestFunctionMap() {
TestFunctionMap BuildTestFunctionMap() {