blob: 55bde9badc8cbb673b8a4d919e0f665da30a69c2 [file] [log] [blame]
// Copyright 2023 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 LIB_LD_TEST_LD_LOAD_ZIRCON_LDSVC_TESTS_BASE_H_
#define LIB_LD_TEST_LD_LOAD_ZIRCON_LDSVC_TESTS_BASE_H_
#include <lib/elfldltl/soname.h>
#include <lib/elfldltl/testing/get-test-data.h>
#include <lib/ld/testing/mock-loader-service.h>
#include <lib/zx/result.h>
#include <lib/zx/vmo.h>
#include <filesystem>
#include <initializer_list>
#include <string_view>
#include "ld-load-tests-base.h"
namespace ld::testing {
// This is the common base class for test fixtures that use a
// fuchsia.ldsvc.Loader service and set expectations for the dependencies
// loaded by it. This class proxies calls to the MockLoaderServiceForTest and
// passes the function it should use to retrieve test VMO files.
//
// It takes calls giving ordered expectations for Loader service requests from
// the process under test. These must be used after Load() and before Run()
// in test cases.
class LdLoadZirconLdsvcTestsBase : public LdLoadTestsBase {
public:
~LdLoadZirconLdsvcTestsBase() = default;
// Optionally expect the dynamic linker to send a Config(config) message.
void LdsvcExpectConfig(std::optional<std::string_view> config) {
if (config) {
mock_.ExpectConfig(*config);
}
}
// Prime the MockLoaderService with the VMO for a dependency by name,
// and expect the MockLoader to load that dependency for the test.
void LdsvcExpectDependency(std::string_view name) { mock_.ExpectDependency(name); }
zx::channel TakeLdsvc() { return mock_.TakeLdsvc(); }
zx::vmo GetLibVmo(std::string_view name) { return mock_.GetVmo(name); }
static std::string FindInterp(zx::unowned_vmo vmo);
void VerifyAndClearNeeded() { mock_.VerifyAndClearExpectations(); }
void LdsvcPathPrefix(std::string_view executable,
std::optional<std::string_view> libprefix = std::nullopt);
// Use the PT_INTERP string to update LdsvcPathPrefix() and then return the
// config found, which can be passed to LdsvcExpectConfig(). The optional
// argument makes it a failure if the extract Config() string doesn't match,
// and doesn't change LdsvcPathPrefix().
std::optional<std::string> ConfigFromInterp(
const std::filesystem::path& interp,
std::optional<std::string_view> expected_config = std::nullopt);
// The same, but extract the PT_INTERP string from the executable file VMO.
std::optional<std::string> ConfigFromInterp(
zx::unowned_vmo executable_vmo,
std::optional<std::string_view> expected_config = std::nullopt) {
return ConfigFromInterp(FindInterp(executable_vmo->borrow()), expected_config);
}
// This just combines GetExecutableVmo, FindInterp, ConfigFromInterp, and
// LdsvcExpectConfig.
zx::vmo GetExecutableVmoWithInterpConfig(
std::string_view executable, std::optional<std::string_view> expected_config = std::nullopt);
// Uses to TestElfLoadSet::Get(test_name) to do Needed() within the test's
// package namespace based on the libprefix found in the TestElfObject data
// rather than a PT_INTERP in the file.
void NeededViaLoadSet(elfldltl::Soname<> set_name, std::initializer_list<std::string_view> names);
protected:
zx::vmo GetInterp(std::string_view executable_name,
std::optional<std::string_view> expected_config);
void LdsvcExpectNeeded() {
for (const auto& [name, found] : TakeNeededLibs()) {
if (found) {
mock_.ExpectDependency(name);
} else {
mock_.ExpectMissing(name);
}
}
}
MockLoaderServiceForTest& mock() { return mock_; }
private:
MockLoaderServiceForTest mock_;
};
} // namespace ld::testing
#endif // LIB_LD_TEST_LD_LOAD_ZIRCON_LDSVC_TESTS_BASE_H_