blob: 471b84f1cd5ba557fee81c06580e5754c690462d [file] [log] [blame]
// Copyright 2021 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 <fuchsia/component/cpp/fidl.h>
#include <fuchsia/component/sandbox/cpp/fidl.h>
#include <fuchsia/settings/cpp/fidl.h>
#include <fuchsia/settings/test/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/namespace.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <atomic>
#include <optional>
#include <string>
#include <zxtest/zxtest.h>
namespace {
// TODO(https://fxbug.dev/330610053): Once a C++ realm_proxy library is available, use
// that instead of this custom boilerplate
class InstalledNamespace {
public:
InstalledNamespace(std::string prefix, zx::channel realm_factory)
: prefix_(std::move(prefix)), realm_factory_(std::move(realm_factory)) {
ZX_ASSERT_MSG(!prefix_.empty(), "prefix cannot be empty");
}
InstalledNamespace(InstalledNamespace&& rhs) = default;
~InstalledNamespace() {
if (prefix_.empty()) {
return;
}
fdio_ns_t* ns;
EXPECT_EQ(fdio_ns_get_installed(&ns), ZX_OK);
EXPECT_EQ(fdio_ns_unbind(ns, prefix_.c_str()), ZX_OK);
}
zx_status_t Connect(const std::string& interface_name, zx::channel request) const {
const std::string path = prefix_ + "/" + interface_name;
return fdio_service_connect(path.c_str(), request.release());
}
static InstalledNamespace Create(sys::ComponentContext* context);
const std::string& prefix() const { return prefix_; }
private:
std::string prefix_;
/// This is not used, but it keeps the RealmFactory connection alive.
///
/// The RealmFactory server may use this connection to pin the lifetime of the realm created
/// for the test.
zx::channel realm_factory_;
};
std::atomic_int32_t namespace_ctr{1};
class PrivacyTest : public zxtest::Test {
protected:
void SetUp() override {
EXPECT_EQ(ZX_OK, service->Connect(realm_factory.NewRequest()));
fuchsia::settings::test::RealmOptions options;
fuchsia::settings::test::RealmFactory_CreateRealm2_Result result1;
fuchsia::component::sandbox::DictionarySyncPtr dictionary;
EXPECT_OK(realm_factory->CreateRealm2(std::move(options), dictionary.NewRequest(), &result1));
test_ns_.emplace(ExtendNamespace(realm_factory.Unbind(), dictionary.Unbind()));
EXPECT_OK(test_ns_->Connect("fuchsia.settings.Privacy", privacy.NewRequest().TakeChannel()));
}
void TearDown() override {
fuchsia::settings::PrivacySettings settings;
settings.set_user_data_sharing_consent(GetInitValue());
fuchsia::settings::Privacy_Set_Result result;
fuchsia::settings::PrivacySettings got_settings;
// Set back to the initial settings and verify.
EXPECT_EQ(ZX_OK, privacy->Set(std::move(settings), &result));
EXPECT_EQ(ZX_OK, privacy->Watch(&got_settings));
EXPECT_TRUE(got_settings.user_data_sharing_consent());
}
bool GetInitValue() const { return this->init_user_data_sharing_consent; }
fuchsia::settings::PrivacySyncPtr privacy;
private:
// TODO(https://fxbug.dev/330610053): Once a C++ realm_proxy library is available, use
// that instead of this custom boilerplate
template <typename Interface>
InstalledNamespace ExtendNamespace(
fidl::InterfaceHandle<Interface> realm_factory,
fidl::InterfaceHandle<::fuchsia::component::sandbox::Dictionary> dictionary) {
std::string prefix = std::string("/dict-") + std::to_string(namespace_ctr++);
fuchsia::component::NamespaceSyncPtr namespace_proxy;
EXPECT_OK(service->Connect(namespace_proxy.NewRequest()));
std::vector<fuchsia::component::NamespaceInputEntry> entries;
entries.emplace_back(fuchsia::component::NamespaceInputEntry{
.path = prefix,
.dictionary = std::move(dictionary),
});
fuchsia::component::Namespace_Create_Result result;
EXPECT_OK(namespace_proxy->Create(std::move(entries), &result));
EXPECT_TRUE(!result.is_err());
std::vector<fuchsia::component::NamespaceEntry> namespace_entries =
std::move(result.response().entries);
EXPECT_EQ(namespace_entries.size(), 1);
auto& entry = namespace_entries[0];
EXPECT_TRUE(entry.has_path() && entry.has_directory());
EXPECT_EQ(entry.path(), prefix);
fdio_ns_t* ns;
EXPECT_OK(fdio_ns_get_installed(&ns));
zx_handle_t dir_handle = entry.mutable_directory()->TakeChannel().release();
EXPECT_OK(fdio_ns_bind(ns, prefix.c_str(), dir_handle));
return InstalledNamespace(std::move(prefix), realm_factory.TakeChannel());
}
fuchsia::settings::test::RealmFactorySyncPtr realm_factory;
std::shared_ptr<sys::ServiceDirectory> service = sys::ServiceDirectory::CreateFromNamespace();
std::optional<InstalledNamespace> test_ns_;
bool init_user_data_sharing_consent = true;
};
// Tests that Set() results in an update to privacy settings.
TEST_F(PrivacyTest, Set) {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
ASSERT_EQ(loop.StartThread(), ZX_OK);
// Setup initial PrivacySettings.
fuchsia::settings::PrivacySettings settings;
fuchsia::settings::Privacy_Set_Result result;
settings.set_user_data_sharing_consent(GetInitValue());
EXPECT_EQ(ZX_OK, privacy->Set(std::move(settings), &result));
// Verify initial settings.
fuchsia::settings::PrivacySettings got_settings;
EXPECT_EQ(ZX_OK, privacy->Watch(&got_settings));
EXPECT_TRUE(got_settings.user_data_sharing_consent());
// Flip the settings.
fuchsia::settings::PrivacySettings new_settings;
new_settings.set_user_data_sharing_consent(false);
EXPECT_EQ(ZX_OK, privacy->Set(std::move(new_settings), &result));
// Verify the new settings.
EXPECT_EQ(ZX_OK, privacy->Watch(&got_settings));
EXPECT_FALSE(got_settings.user_data_sharing_consent());
}
} // namespace