blob: 645fe1089407b138af8458ce4e1201492c1d45c2 [file] [log] [blame]
// Copyright 2022 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 <memory>
#include <gtest/gtest.h>
#include "fuchsia/examples/diagnostics/cpp/fidl.h"
#include "lib/async-loop/cpp/loop.h"
#include "lib/async-loop/loop.h"
#include "lib/async/dispatcher.h"
#include "lib/fidl/cpp/interface_ptr.h"
#include "profile.h"
#include "src/lib/files/path.h"
#include "src/lib/testing/loop_fixture/real_loop_fixture.h"
class ProfileTests : public gtest::RealLoopFixture {
public:
ProfileTests() : loop_(&kAsyncLoopConfigNeverAttachToThread) { loop_.StartThread(); }
~ProfileTests() override { loop_.Shutdown(); }
std::shared_ptr<Profile> CreateNewProfile(std::string key) {
auto p = std::make_shared<Profile>(loop_.dispatcher(), files::JoinPath("/data", key));
// profile will run on its own thread, so save it so that it doesn't die before loop variable.
profiles_.push_back(p);
return p;
}
void StopServingProfiles() {
loop_.RunUntilIdle();
loop_.Quit();
profiles_.clear();
loop_.JoinThreads();
loop_.ResetQuit();
loop_.StartThread();
}
fidl::InterfacePtr<fuchsia::examples::diagnostics::Profile> GetHandler(
const std::shared_ptr<Profile>& profile) {
fidl::InterfacePtr<fuchsia::examples::diagnostics::Profile> ptr;
profile->AddBinding(ptr.NewRequest(dispatcher()));
return ptr;
}
fidl::InterfacePtr<fuchsia::examples::diagnostics::ProfileReader> GetReaderHandler(
const std::shared_ptr<Profile>& profile) {
fidl::InterfacePtr<fuchsia::examples::diagnostics::ProfileReader> ptr;
profile->AddReaderBinding(ptr.NewRequest(dispatcher()));
return ptr;
}
private:
std::vector<std::shared_ptr<Profile>> profiles_;
async::Loop loop_;
};
TEST_F(ProfileTests, Name) {
auto profile = CreateNewProfile("Name");
auto client = GetHandler(profile);
std::string name = "placeholder";
client->GetName([&](std::string n) { name = std::move(n); });
RunLoopUntil([&]() { return name != "placeholder"; });
EXPECT_EQ(name, "");
std::string set_name = "my_name";
client->SetName(set_name);
client->GetName([&](std::string n) { name = std::move(n); });
RunLoopUntil([&]() { return !name.empty(); });
EXPECT_EQ(name, set_name);
}
TEST_F(ProfileTests, Balance) {
auto profile = CreateNewProfile("Balance");
auto client = GetHandler(profile);
int64_t balance = -1;
int64_t old_balance = balance;
client->GetBalance([&](int64_t b) { balance = b; });
RunLoopUntil([&]() { return balance != old_balance; });
EXPECT_EQ(balance, 0);
old_balance = balance;
// Add balance
client->AddBalance(4);
client->WithdrawBalance(2, [](bool status) { ASSERT_TRUE(status); });
client->AddBalance(10);
client->WithdrawBalance(13, [](bool status) {
// balance cannot go into negative so we should get false.
ASSERT_FALSE(status);
});
client->GetBalance([&](int64_t b) { balance = b; });
RunLoopUntil([&]() { return balance != old_balance; });
EXPECT_EQ(balance, 12);
// make sure we can withdraw all balance
old_balance = balance;
client->WithdrawBalance(12, [](bool status) { ASSERT_TRUE(status); });
client->GetBalance([&](int64_t b) { balance = b; });
RunLoopUntil([&]() { return balance != old_balance; });
EXPECT_EQ(balance, 0);
}
TEST_F(ProfileTests, Persists) {
std::string name = "";
int64_t balance = -1;
std::string set_name = "my_name";
auto profile = CreateNewProfile("Persists");
auto client = GetHandler(profile);
client->SetName(set_name);
client->AddBalance(10);
client->GetName([&](std::string n) { name = std::move(n); });
client->GetBalance([&](int64_t b) { balance = b; });
RunLoopUntil([&]() { return !name.empty() && balance != -1; });
EXPECT_EQ(name, set_name);
EXPECT_EQ(balance, 10);
client.Unbind();
StopServingProfiles();
// A profile created with the same key should contain the same information.
auto profile2 = CreateNewProfile("Persists");
auto client2 = GetHandler(profile2);
name = "";
balance = -1;
client2->GetName([&](std::string n) { name = std::move(n); });
client2->GetBalance([&](int64_t b) { balance = b; });
RunLoopUntil([&]() { return !name.empty() && balance != -1; });
EXPECT_EQ(name, set_name);
EXPECT_EQ(balance, 10);
}
// Test that reader can read latest changes to profile.
// Disabled because it is flaky.
TEST_F(ProfileTests, DISABLED_NameWithReader) {
auto profile = CreateNewProfile("NameWithReader");
auto client = GetHandler(profile);
auto reader = GetReaderHandler(profile);
std::string name = "placeholder";
std::string set_name = "my_name";
client->SetName(set_name);
reader->GetName([&](std::string n) { name = std::move(n); });
RunLoopUntil([&]() { return name != "placeholder"; });
// Flakes sometimes, this will flake much more in an integration tests.
EXPECT_EQ(name, set_name);
}
// Test that reader can read latest changes to profile.
// Disabled because it is flaky.
TEST_F(ProfileTests, DISABLED_BalanceWithReader) {
auto profile = CreateNewProfile("BalanceWithReader");
auto client = GetHandler(profile);
auto reader = GetReaderHandler(profile);
int64_t balance = -1;
int64_t old_balance = balance;
// Add balance
client->AddBalance(4);
client->WithdrawBalance(2, [](bool status) { ASSERT_TRUE(status); });
reader->GetBalance([&](int64_t b) { balance = b; });
RunLoopUntil([&]() { return balance != old_balance; });
// flaky test and fails more often. Server has a race condition even though
// it is single threaded.
EXPECT_EQ(balance, 2);
}