blob: fd6b2871fff1af8eaa6dadd1f6861b989fc073e8 [file] [log] [blame]
// Copyright 2019 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.
#ifndef SRC_MEDIA_AUDIO_AUDIO_CORE_TESTING_THREADING_MODEL_FIXTURE_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_TESTING_THREADING_MODEL_FIXTURE_H_
#include <lib/async-testing/test_loop.h>
#include <lib/async/cpp/executor.h>
#include <lib/async/dispatcher.h>
#include <lib/sys/cpp/testing/component_context_provider.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/compiler.h>
#include "src/lib/testing/loop_fixture/test_loop_fixture.h"
#include "src/media/audio/audio_core/context.h"
#include "src/media/audio/audio_core/testing/fake_plug_detector.h"
#include "src/media/audio/audio_core/testing/test_process_config.h"
#include "src/media/audio/audio_core/threading_model.h"
namespace media::audio::testing {
// Implements a |ThreadingModel| on top of the |async::TestLoop| to enable easily writing unit tests
// against components that depend on |ThreadingModel|.
class TestThreadingModel : public ThreadingModel {
public:
explicit TestThreadingModel(async::TestLoop* test_loop) : loop_(test_loop) {}
~TestThreadingModel() override = default;
// |ThreadingModel|
ExecutionDomain& FidlDomain() override { return fidl_holder_.domain; }
ExecutionDomain& IoDomain() override { return io_holder_.domain; }
OwnedDomainPtr AcquireMixDomain(const std::string& name) override {
return OwnedDomainPtr(&mix_holder_.domain, [](ExecutionDomain*) {});
}
void Quit() override { loop_->Quit(); }
// Note we should never call this on the |TestThreadingModel|. Execution should instead be
// controlled using the |async::TestLoop| used to construct this |ThreadingModel|.
void RunAndJoinAllThreads() override {
FX_CHECK(false) << "RunAndJoinAllThreads not supported on TestThreadingModel.";
}
private:
struct DomainHolder {
DomainHolder(async::TestLoop* test_loop, const std::string& name)
: loop(test_loop->StartNewLoop()),
executor(loop->dispatcher()),
domain{loop->dispatcher(), &executor, name} {}
std::unique_ptr<async::LoopInterface> loop;
async::Executor executor;
ExecutionDomain domain;
};
async::TestLoop* loop_;
DomainHolder fidl_holder_{loop_, "fidl"};
DomainHolder io_holder_{loop_, "io"};
DomainHolder mix_holder_{loop_, "mix"};
};
// A test fixture that provides a |ThreadingModel| on top of an |async::TestLoop|. We inherit from
// |gtest::TestLoopFixture| to make it simple to convert tests that are already using test loops.
//
// Ex:
// TEST_F(MyTest, Foo) {
// UnderTest bar(&threading_model());
// bar.ScheduleSomeWork();
// RunLoopUntilIdle();
//
// AssertScheduledWorkCompleted(&bar);
// }
class ThreadingModelFixture : public gtest::TestLoopFixture {
public:
ThreadingModelFixture(ProcessConfig config) : process_config_(std::move(config)) { Init(); }
ThreadingModelFixture() { Init(); }
protected:
// This threading model will be backed by an |async::TestLoop|. Control the loop using the methods
// in |gtest::TestLoopFixture|.
ThreadingModel& threading_model() { return context_->threading_model(); };
Context& context() { return *context_; }
FakePlugDetector* fake_plug_detector() const { return fake_plug_detector_; }
private:
void Init() {
auto threading_model = std::make_unique<TestThreadingModel>(&test_loop());
auto plug_detector = std::make_unique<testing::FakePlugDetector>();
fake_plug_detector_ = plug_detector.get();
context_ =
Context::Create(std::move(threading_model), component_context_provider_.TakeContext(),
std::move(plug_detector), ProcessConfig::instance());
}
TestProcessConfig process_config_;
TestThreadingModel threading_model_{&test_loop()};
sys::testing::ComponentContextProvider component_context_provider_;
testing::FakePlugDetector* fake_plug_detector_;
std::unique_ptr<Context> context_;
};
} // namespace media::audio::testing
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_TESTING_THREADING_MODEL_FIXTURE_H_