|  | // Copyright 2020 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <lib/async-loop/cpp/loop.h> | 
|  | #include <lib/fdio/fd.h> | 
|  | #include <lib/procfs/cpp/process.h> | 
|  | #include <lib/zx/channel.h> | 
|  |  | 
|  | #include <memory> | 
|  | #include <utility> | 
|  |  | 
|  | #include <fbl/unique_fd.h> | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "src/lib/files/file.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class ProcessHost { | 
|  | public: | 
|  | ProcessHost() | 
|  | : loop_(&kAsyncLoopConfigNeverAttachToThread), | 
|  | process_dir_(procfs::CreateProcessDir(loop_.dispatcher())) { | 
|  | loop_.StartThread("procfs test thread"); | 
|  | } | 
|  |  | 
|  | ~ProcessHost() { | 
|  | loop_.Shutdown(); | 
|  | } | 
|  |  | 
|  | // The returned file descriptor must be closed before the |ProcessHost| is destructed. | 
|  | fbl::unique_fd Open(uint32_t flags = fuchsia::io::OPEN_RIGHT_READABLE) { | 
|  | zx::channel client_end, server_end; | 
|  | zx_status_t status = zx::channel::create(0, &client_end, &server_end); | 
|  | if (status != ZX_OK) { | 
|  | return fbl::unique_fd(); | 
|  | } | 
|  | status = process_dir_->Serve(flags, std::move(server_end), loop_.dispatcher()); | 
|  | if (status != ZX_OK) { | 
|  | return fbl::unique_fd(); | 
|  | } | 
|  |  | 
|  | fbl::unique_fd fd; | 
|  | status = fdio_fd_create(client_end.release(), fd.reset_and_get_address()); | 
|  | if (status != ZX_OK) { | 
|  | return fbl::unique_fd(); | 
|  | } | 
|  | return fd; | 
|  | } | 
|  |  | 
|  | private: | 
|  | async::Loop loop_; | 
|  | std::unique_ptr<vfs::PseudoDir> process_dir_; | 
|  | }; | 
|  |  | 
|  | TEST(ProcessDir, ReadEnviron) { | 
|  | ProcessHost host; | 
|  | auto fd = host.Open(); | 
|  | ASSERT_TRUE(fd.is_valid()); | 
|  |  | 
|  | std::string content; | 
|  | ASSERT_TRUE(files::ReadFileToStringAt(fd.get(), "environ", &content)); | 
|  | EXPECT_EQ(std::string::npos, content.find("THE_TEXT_WE_EXPECT")); | 
|  |  | 
|  | setenv("PROCFS_TEST_VAR", "THE_TEXT_WE_EXPECT", 1); | 
|  |  | 
|  | ASSERT_TRUE(files::ReadFileToStringAt(fd.get(), "environ", &content)); | 
|  | EXPECT_NE(std::string::npos, content.find("THE_TEXT_WE_EXPECT")); | 
|  |  | 
|  | unsetenv("PROCFS_TEST_VAR"); | 
|  |  | 
|  | ASSERT_TRUE(files::ReadFileToStringAt(fd.get(), "environ", &content)); | 
|  | EXPECT_EQ(std::string::npos, content.find("THE_TEXT_WE_EXPECT")); | 
|  | } | 
|  |  | 
|  | TEST(ProcessDir, CurrentWorkingDirectory) { | 
|  | ProcessHost host; | 
|  | auto fd = host.Open(); | 
|  | ASSERT_TRUE(fd.is_valid()); | 
|  |  | 
|  | char buffer[PATH_MAX]; | 
|  | getcwd(buffer, sizeof(buffer)); | 
|  |  | 
|  | ASSERT_EQ(0, chdir("/pkg/test")); | 
|  |  | 
|  | fbl::unique_fd cwd(openat(fd.get(), "cwd", O_DIRECTORY | O_RDONLY)); | 
|  | ASSERT_TRUE(cwd.is_valid()); | 
|  |  | 
|  | fbl::unique_fd probe(openat(cwd.get(), "procfs_cpp_unittests", O_RDONLY)); | 
|  | ASSERT_TRUE(probe.is_valid()); | 
|  |  | 
|  | ASSERT_EQ(0, chdir("/pkg/lib")); | 
|  |  | 
|  | probe.reset(openat(cwd.get(), "procfs_cpp_unittests", O_DIRECTORY | O_RDONLY)); | 
|  | ASSERT_FALSE(probe.is_valid()); | 
|  |  | 
|  | ASSERT_EQ(0, chdir(buffer)); | 
|  | } | 
|  |  | 
|  | }  // namespace |