blob: 590312bc6ff4497561c78416b432dc2fb04e4192 [file] [log] [blame]
// Copyright 2024 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 <fcntl.h>
#include <fidl/fuchsia.examples/cpp/wire.h>
#include <lib/async-testing/test_loop.h>
#include <lib/component/incoming/cpp/directory_watcher.h>
#include <lib/fdio/namespace.h>
#include <stdlib.h>
#include <zircon/types.h>
#include <fbl/unique_fd.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace component {
namespace {
const char* kFakeServicePath = "/svc_test";
namespace testing {
class TestBase : public ::testing::Test {
protected:
int MkDir(std::string dir) {
std::string path = svc_ + dir;
return mkdir(path.data(), 066);
}
private:
std::string svc_;
void SetUp() override {
char buf[] = "/tmp/svc.XXXXXX";
svc_ = mkdtemp(buf);
int ret = MkDir("/fuchsia.examples.EchoService");
ASSERT_EQ(0, ret);
ret = MkDir("/fuchsia.examples.EchoService/default");
ASSERT_EQ(0, ret);
ret = MkDir("/fuchsia.examples.EchoService/my_instance");
ASSERT_EQ(0, ret);
fbl::unique_fd fd(open(svc_.data(), O_RDONLY | O_DIRECTORY));
ASSERT_TRUE(fd.is_valid());
fdio_ns_t* ns;
ASSERT_EQ(ZX_OK, fdio_ns_get_installed(&ns));
zx_status_t status = fdio_ns_bind_fd(ns, kFakeServicePath, fd.get());
ASSERT_EQ(ZX_OK, status);
}
void TearDown() override {
fdio_ns_t* ns;
ASSERT_EQ(ZX_OK, fdio_ns_get_installed(&ns));
ASSERT_EQ(ZX_OK, fdio_ns_unbind(ns, kFakeServicePath));
}
};
} // namespace testing
class DirectoryWatcherTest : public testing::TestBase {
protected:
async::TestLoop& loop() { return loop_; }
private:
async::TestLoop loop_;
};
TEST_F(DirectoryWatcherTest, Begin) {
std::vector<std::pair<fuchsia_io::wire::WatchEvent, std::string>> instances;
DirectoryWatcher watcher;
auto callback = ([&instances](fuchsia_io::wire::WatchEvent event, std::string instance) {
instances.emplace_back(std::make_pair(event, std::move(instance)));
});
std::string service_dir = std::string(kFakeServicePath) + "/fuchsia.examples.EchoService";
zx::result dir_result = OpenDirectory(service_dir);
ASSERT_TRUE(dir_result.is_ok());
zx_status_t status = watcher.Begin(dir_result.value(), callback, loop().dispatcher());
ASSERT_EQ(ZX_OK, status);
ASSERT_TRUE(loop().RunUntilIdle());
// These instances are added by TestBase:
EXPECT_THAT(instances, ::testing::UnorderedElementsAre(
std::make_pair(fuchsia_io::wire::WatchEvent::kExisting, "default"),
std::make_pair(fuchsia_io::wire::WatchEvent::kExisting, "my_instance"),
std::make_pair(fuchsia_io::wire::WatchEvent::kIdle, "")));
instances.clear();
int ret = MkDir("/fuchsia.examples.EchoService/added");
ASSERT_EQ(0, ret);
ASSERT_TRUE(loop().RunUntilIdle());
EXPECT_THAT(instances, ::testing::UnorderedElementsAre(
std::make_pair(fuchsia_io::wire::WatchEvent::kAdded, "added")));
status = watcher.Cancel();
ASSERT_EQ(ZX_OK, status);
instances.clear();
ret = MkDir("/fuchsia.examples.EchoService/added-after");
ASSERT_EQ(0, ret);
ASSERT_FALSE(loop().RunUntilIdle());
ASSERT_TRUE(instances.empty());
}
TEST_F(DirectoryWatcherTest, SyncDirectoryWatcher) {
std::vector<std::string> instances;
std::string service_dir = std::string(kFakeServicePath) + "/fuchsia.examples.EchoService";
SyncDirectoryWatcher watcher(service_dir);
zx::result watch_result = watcher.GetNextEntry(true);
ASSERT_TRUE(watch_result.is_ok());
instances.push_back(watch_result.value());
watch_result = watcher.GetNextEntry(true);
ASSERT_TRUE(watch_result.is_ok());
instances.push_back(watch_result.value());
watch_result = watcher.GetNextEntry(true);
ASSERT_EQ(watch_result.status_value(), ZX_ERR_STOP);
// These instances are added by TestBase:
EXPECT_THAT(instances, ::testing::UnorderedElementsAre("default", "my_instance"));
}
} // namespace
} // namespace component