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

Commit bd130567 authored by Tom Cherry's avatar Tom Cherry Committed by Gerrit Code Review
Browse files

Merge "ueventd: add a test for ueventd_parser.cpp"

parents 5fd5be33 5f0198bf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -180,6 +180,7 @@ cc_test {
        "service_test.cpp",
        "subcontext_test.cpp",
        "tokenizer_test.cpp",
        "ueventd_parser_test.cpp",
        "ueventd_test.cpp",
        "util_test.cpp",
    ],
+17 −10
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ namespace init {

class Permissions {
  public:
    friend void TestPermissions(const Permissions& expected, const Permissions& test);

    Permissions(const std::string& name, mode_t perm, uid_t uid, gid_t gid);

    bool Match(const std::string& path) const;
@@ -57,6 +59,8 @@ class Permissions {

class SysfsPermissions : public Permissions {
  public:
    friend void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test);

    SysfsPermissions(const std::string& name, const std::string& attribute, mode_t perm, uid_t uid,
                     gid_t gid)
        : Permissions(name, perm, uid, gid), attribute_(attribute) {}
@@ -71,14 +75,22 @@ class SysfsPermissions : public Permissions {
class Subsystem {
  public:
    friend class SubsystemParser;
    friend void TestSubsystems(const Subsystem& expected, const Subsystem& test);

    enum DevnameSource {
        DEVNAME_UEVENT_DEVNAME,
        DEVNAME_UEVENT_DEVPATH,
    };

    Subsystem() {}
    Subsystem(std::string name) : name_(std::move(name)) {}
    Subsystem(const std::string& name) : name_(name) {}
    Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name)
        : name_(name), devname_source_(source), dir_name_(dir_name) {}

    // Returns the full path for a uevent of a device that is a member of this subsystem,
    // according to the rules parsed from ueventd.rc
    std::string ParseDevPath(const Uevent& uevent) const {
        std::string devname = devname_source_ == DevnameSource::DEVNAME_UEVENT_DEVNAME
        std::string devname = devname_source_ == DEVNAME_UEVENT_DEVNAME
                                      ? uevent.device_name
                                      : android::base::Basename(uevent.path);

@@ -88,14 +100,9 @@ class Subsystem {
    bool operator==(const std::string& string_name) const { return name_ == string_name; }

  private:
    enum class DevnameSource {
        DEVNAME_UEVENT_DEVNAME,
        DEVNAME_UEVENT_DEVPATH,
    };

    std::string name_;
    DevnameSource devname_source_ = DEVNAME_UEVENT_DEVNAME;
    std::string dir_name_ = "/dev";
    DevnameSource devname_source_;
};

class DeviceHandler {
+2 −2
Original line number Diff line number Diff line
@@ -117,11 +117,11 @@ Result<Success> SubsystemParser::ParseSection(std::vector<std::string>&& args,

Result<Success> SubsystemParser::ParseDevName(std::vector<std::string>&& args) {
    if (args[1] == "uevent_devname") {
        subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVNAME;
        subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVNAME;
        return Success();
    }
    if (args[1] == "uevent_devpath") {
        subsystem_.devname_source_ = Subsystem::DevnameSource::DEVNAME_UEVENT_DEVPATH;
        subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVPATH;
        return Success();
    }

+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */

#include "ueventd_parser.h"

#include <android-base/test_utils.h>
#include <gtest/gtest.h>
#include <private/android_filesystem_config.h>

namespace android {
namespace init {

void TestSubsystems(const Subsystem& expected, const Subsystem& test) {
    EXPECT_EQ(expected.name_, test.name_);
    EXPECT_EQ(expected.devname_source_, test.devname_source_) << expected.name_;
    EXPECT_EQ(expected.dir_name_, test.dir_name_) << expected.name_;
}

void TestPermissions(const Permissions& expected, const Permissions& test) {
    EXPECT_EQ(expected.name_, test.name_);
    EXPECT_EQ(expected.perm_, test.perm_) << expected.name_;
    EXPECT_EQ(expected.uid_, test.uid_) << expected.name_;
    EXPECT_EQ(expected.gid_, test.gid_) << expected.name_;
    EXPECT_EQ(expected.prefix_, test.prefix_) << expected.name_;
    EXPECT_EQ(expected.wildcard_, test.wildcard_) << expected.name_;
}

void TestSysfsPermissions(const SysfsPermissions& expected, const SysfsPermissions& test) {
    TestPermissions(expected, test);
    EXPECT_EQ(expected.attribute_, test.attribute_);
}

template <typename T, typename F>
void TestVector(const T& expected, const T& test, F function) {
    ASSERT_EQ(expected.size(), test.size());
    auto expected_it = expected.begin();
    auto test_it = test.begin();

    for (; expected_it != expected.end(); ++expected_it, ++test_it) {
        function(*expected_it, *test_it);
    }
}

void TestUeventdFile(const std::string& content, const UeventdConfiguration& expected) {
    TemporaryFile tf;
    ASSERT_TRUE(tf.fd != -1);
    ASSERT_TRUE(android::base::WriteStringToFd(content, tf.fd));

    auto result = ParseConfig({tf.path});

    TestVector(expected.subsystems, result.subsystems, TestSubsystems);
    TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions);
    TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions);
    EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
}

TEST(ueventd_parser, EmptyFile) {
    TestUeventdFile("", {});
}

TEST(ueventd_parser, Subsystems) {
    auto ueventd_file = R"(
subsystem test_devname
    devname uevent_devname

subsystem test_devpath_no_dirname
    devname uevent_devpath

subsystem test_devname2
    devname uevent_devname

subsystem test_devpath_dirname
    devname uevent_devpath
    dirname /dev/graphics
)";

    auto subsystems = std::vector<Subsystem>{
            {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
            {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
            {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
            {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};

    TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}});
}

TEST(ueventd_parser, Permissions) {
    auto ueventd_file = R"(
/dev/rtc0                 0640   system     system
/dev/graphics/*           0660   root       graphics
/dev/*/test               0660   root       system

/sys/devices/platform/trusty.*      trusty_version        0440  root   log
/sys/devices/virtual/input/input   enable      0660  root   input
/sys/devices/virtual/*/input   poll_delay  0660  root   input
)";

    auto permissions = std::vector<Permissions>{
            {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM},
            {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS},
            {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM},
    };

    auto sysfs_permissions = std::vector<SysfsPermissions>{
            {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG},
            {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT},
            {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT},
    };

    TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}});
}

TEST(ueventd_parser, FirmwareDirectories) {
    auto ueventd_file = R"(
firmware_directories /first/ /second /third
firmware_directories /more
)";

    auto firmware_directories = std::vector<std::string>{
            "/first/",
            "/second",
            "/third",
            "/more",
    };

    TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories});
}

TEST(ueventd_parser, AllTogether) {
    auto ueventd_file = R"(

/dev/rtc0                 0640   system     system
firmware_directories /first/ /second /third
/sys/devices/platform/trusty.*      trusty_version        0440  root   log

subsystem test_devname
    devname uevent_devname

/dev/graphics/*           0660   root       graphics

subsystem test_devpath_no_dirname
    devname uevent_devpath

/sys/devices/virtual/input/input   enable      0660  root   input

## this is a comment

subsystem test_devname2
## another comment
    devname uevent_devname

subsystem test_devpath_dirname
    devname uevent_devpath
    dirname /dev/graphics

/dev/*/test               0660   root       system
/sys/devices/virtual/*/input   poll_delay  0660  root   input
firmware_directories /more

#ending comment
)";

    auto subsystems = std::vector<Subsystem>{
            {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
            {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"},
            {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"},
            {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}};

    auto permissions = std::vector<Permissions>{
            {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM},
            {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS},
            {"/dev/*/test", 0660, AID_ROOT, AID_SYSTEM},
    };

    auto sysfs_permissions = std::vector<SysfsPermissions>{
            {"/sys/devices/platform/trusty.*", "trusty_version", 0440, AID_ROOT, AID_LOG},
            {"/sys/devices/virtual/input/input", "enable", 0660, AID_ROOT, AID_INPUT},
            {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT},
    };

    auto firmware_directories = std::vector<std::string>{
            "/first/",
            "/second",
            "/third",
            "/more",
    };

    TestUeventdFile(ueventd_file,
                    {subsystems, sysfs_permissions, permissions, firmware_directories});
}

// All of these lines are ill-formed, so test that there is 0 output.
TEST(ueventd_parser, ParseErrors) {
    auto ueventd_file = R"(

/dev/rtc0                 badmode   baduidbad     system
/dev/rtc0                 0640   baduidbad     system
/dev/rtc0                 0640   system     baduidbad
firmware_directories #no directory listed
/sys/devices/platform/trusty.*      trusty_version        badmode  root   log
/sys/devices/platform/trusty.*      trusty_version        0440  baduidbad   log
/sys/devices/platform/trusty.*      trusty_version        0440  root   baduidbad

subsystem #no name

)";

    TestUeventdFile(ueventd_file, {});
}

}  // namespace init
}  // namespace android