blob: b3d0c974e48918e7a02c7a43cbf3e56a877aa847 [file] [log] [blame]
// 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 <fuchsia/intl/cpp/fidl.h>
#include <fuchsia/settings/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/sys/cpp/testing/test_with_environment.h>
#include <lib/zx/time.h>
#include <zircon/status.h>
using fuchsia::intl::LocaleId;
using fuchsia::intl::Profile;
using fuchsia::intl::TemperatureUnit;
using fuchsia::intl::TimeZoneId;
using fuchsia::settings::Error;
using fuchsia::settings::HourCycle;
using fuchsia::settings::IntlSettings;
static const int32_t kTimeoutSec = 30;
// See README.md for more detail about this test.
class IntlServicesTest : public sys::testing::TestWithEnvironment {
public:
IntlServicesTest()
: deadline_(zx::clock::get_monotonic() + zx::sec(kTimeoutSec)),
ctx_(sys::ComponentContext::CreateAndServeOutgoingDirectory()),
settings_intl_(ctx_->svc()->Connect<fuchsia::settings::Intl>()),
intl_property_provider_(ctx_->svc()->Connect<fuchsia::intl::PropertyProvider>()),
settings_intl_status_(ZX_OK),
intl_property_provider_status_(ZX_OK) {
settings_intl_.set_error_handler(
[this](zx_status_t status) { settings_intl_status_ = status; });
intl_property_provider_.set_error_handler(
[this](zx_status_t status) { intl_property_provider_status_ = status; });
}
// Returns true if any error occurred in the FIDL roundtrip.
bool FIDLError() const {
return intl_property_provider_status_ != ZX_OK || settings_intl_status_ != ZX_OK;
}
// Returns true if timeout occurred. Used so that the tests do not block.
bool Timeout() const {
zx::time now = zx::clock::get_monotonic();
return now > deadline_;
}
protected:
zx::time deadline_;
std::unique_ptr<sys::ComponentContext> ctx_;
fuchsia::settings::IntlPtr settings_intl_;
fuchsia::intl::PropertyProviderPtr intl_property_provider_;
zx_status_t settings_intl_status_;
zx_status_t intl_property_provider_status_;
};
TEST_F(IntlServicesTest, AsyncSetThenGet) {
// Run a dummy GetProfile first, to ensure the event loop is ran until the
// binding from this test's client is registered with the server. This avoids
// a data race between the binding and the notification that may happen below.
// if the first OnChange event is sent out to the server before a binding
// exists, causing this test to miss the OnChange notification.
bool dummy_get_completed{};
auto dummy_get_callback = [&](fuchsia::intl::Profile res) {
dummy_get_completed = true;
};
intl_property_provider_->GetProfile(dummy_get_callback);
RunLoopUntil([&] {
return dummy_get_completed || FIDLError() || Timeout();
});
ASSERT_FALSE(FIDLError());
ASSERT_FALSE(Timeout());
Profile get_result;
bool get_completed{};
auto get_callback = [&](fuchsia::intl::Profile res) {
get_result = std::move(res);
get_completed = true;
};
bool on_change_completed{};
intl_property_provider_.events().OnChange = [&] {
// Reading the profile before OnChange arrives will cause a data race and
// make result comparison flaky in the test.
intl_property_provider_->GetProfile(get_callback);
on_change_completed = true;
};
fit::result<void, Error> set_result;
bool set_completed{};
auto set_callback = [&](fit::result<void, Error> res) {
set_result = std::move(res);
set_completed = true;
};
IntlSettings settings;
settings.set_locales({LocaleId{.id = "ru-RU"}});
settings.set_time_zone_id(TimeZoneId{.id = "Europe/Moscow"});
settings.set_temperature_unit(TemperatureUnit::CELSIUS);
settings.set_hour_cycle(HourCycle::H23);
settings_intl_->Set(std::move(settings), set_callback);
RunLoopUntil([&] {
return (set_completed && get_completed && on_change_completed) || FIDLError() || Timeout();
});
ASSERT_EQ(ZX_OK, settings_intl_status_) << zx_status_get_string(settings_intl_status_);
ASSERT_EQ(ZX_OK, intl_property_provider_status_)
<< zx_status_get_string(intl_property_provider_status_);
// The test should normally run for a fraction of a second, so even though this measures time
// *after* the test events completed, it should not matter for timeout checks.
ASSERT_FALSE(Timeout()) << "Test took too long to complete: "
<< " set_completed=" << set_completed
<< " get_completed=" << get_completed
<< " on_change_completed=" << on_change_completed;
ASSERT_TRUE(set_result.is_ok());
EXPECT_EQ(TemperatureUnit::CELSIUS, get_result.temperature_unit());
EXPECT_EQ("Europe/Moscow", get_result.time_zones()[0].id);
EXPECT_EQ("ru-RU-u-ca-gregory-fw-mon-hc-h23-ms-metric-nu-latn-tz-rumow",
get_result.locales()[0].id)
<< "Expected BCP-47 locale";
}