blob: 584340dc16dbeda65b9702b899cea09b4545480f [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_DEVICES_TESTS_LIBDRIVER_INTEGRATION_TEST_INTEGRATION_TEST_H_
#define SRC_DEVICES_TESTS_LIBDRIVER_INTEGRATION_TEST_INTEGRATION_TEST_H_
#include <fuchsia/io/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/wait.h>
#include <lib/devmgr-integration-test/fixture.h>
#include <lib/fpromise/promise.h>
#include <lib/zx/channel.h>
#include <lib/zx/time.h>
#include <memory>
#include <gtest/gtest.h>
#include "mock-device-hooks.h"
#include "mock-device.h"
#include "root-mock-device.h"
// Wrapper for an assert that converts a failure to a return of a // fpromise::promise<void, const
// char*> that resolves immediately to a fpromise::error()
#define PROMISE_ASSERT(assertion) \
do { \
[&]() { assertion; }(); \
if (testing::Test::HasFatalFailure()) { \
return fpromise::make_error_promise(std::string("Assertion failure")); \
} \
} while (0)
// Wrapper for an assert that converts a failure to a return of a fpromise::error()
#define ERROR_ASSERT(assertion) \
do { \
[&]() { assertion; }(); \
if (testing::Test::HasFatalFailure()) { \
return fpromise::error(std::string("Assertion failure")); \
} \
} while (0)
namespace libdriver_integration_test {
class IntegrationTest : public testing::Test {
public:
static void SetUpTestSuite();
static void TearDownTestSuite();
IntegrationTest();
~IntegrationTest() override;
void SetUp() override;
using Error = std::string;
template <class T>
using Result = fpromise::result<T, Error>;
template <class T>
using Promise = fpromise::promise<T, Error>;
template <class T>
using Completer = fpromise::completer<T, Error>;
using HookInvocation = fuchsia::device::mock::HookInvocation;
// Convenience method on top of ExpectBind for having bind create a child
// and return success.
static Promise<void> CreateFirstChild(std::unique_ptr<RootMockDevice>* root_mock_device,
std::unique_ptr<MockDevice>* child_device);
// Convenience method on top of ExpectUnbind and ExpectRelease for having
// unbind invoke device_remove(), with the belief that that will drop the
// last reference to the device and Release() will be called.
static Promise<void> ExpectUnbindThenRelease(const std::unique_ptr<MockDevice>& device);
// Initializes |root_mock_device| and returns a promise that will be complete after
// the root mock device's bind hook has been called. The bind hook will
// perform the given |actions|.
static Promise<void> ExpectBind(std::unique_ptr<RootMockDevice>* root_mock_device,
BindOnce::Callback actions_callback);
// Returns a promise that will be complete after the device invokes its
// unbind() hook and performs the given |actions|. |device| must outlive
// this promise.
static Promise<void> ExpectUnbind(const std::unique_ptr<MockDevice>& device,
UnbindOnce::Callback actions_callback);
// Returns a promise that will be complete after the device invokes its
// release() hook. |device| must outive this promise.
static Promise<void> ExpectRelease(const std::unique_ptr<MockDevice>& device);
// Performs an open of the given |path| relative to the devfs, and puts the
// connection into |client|. The promise returned completes when the open
// result is sent. We must setup an open hook handler in order for that
// promise to be completed.
Promise<void> DoOpen(const std::string& path, fidl::InterfacePtr<fuchsia::io::Node>* client);
// Waits for the given |path| relative to devfs to be available. Currently
// waiting for paths in which non-terminal directories don't yet exist is
// not supported.
Promise<void> DoWaitForPath(const std::string& path);
// Joins two promises and collapses the results such that if either failed
// the returned promise fails.
static auto JoinPromises(Promise<void> promise1, Promise<void> promise2) {
return join_promises(std::move(promise1), std::move(promise2))
.then([](fpromise::result<std::tuple<Result<void>, Result<void>>>& wrapped_results)
-> Result<void> {
// join_promises() can't fail, so just extract the value
auto results = wrapped_results.value();
if (std::get<0>(results).is_error()) {
return std::get<0>(results);
}
return std::get<1>(results);
});
}
// Run the given promise and transform its error case into a test failure.
static void RunPromise(Promise<void> promise);
protected:
static void DoSetup();
using IsolatedDevmgr = devmgr_integration_test::IsolatedDevmgr;
static IsolatedDevmgr devmgr_;
static async::Loop loop_;
fidl::InterfacePtr<fuchsia::io::Directory> devfs_;
};
} // namespace libdriver_integration_test
#endif // SRC_DEVICES_TESTS_LIBDRIVER_INTEGRATION_TEST_INTEGRATION_TEST_H_