libcryfs/test/cryfs-cli/testutils/CliTest.h

108 lines
4.6 KiB
C
Raw Normal View History

2015-10-29 19:34:36 +01:00
#pragma once
#ifndef MESSMER_CRYFS_TEST_CLI_TESTUTILS_CLITEST_H
#define MESSMER_CRYFS_TEST_CLI_TESTUTILS_CLITEST_H
2018-09-07 14:00:47 +02:00
#if defined(_MSC_VER)
#include <codecvt>
#include <dokan/dokan.h>
#endif
2016-02-11 16:39:42 +01:00
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <cpp-utils/tempfile/TempDir.h>
#include <cpp-utils/tempfile/TempFile.h>
#include <cryfs-cli/Cli.h>
#include <cryfs-cli/VersionChecker.h>
2016-02-11 16:39:42 +01:00
#include <cpp-utils/logging/logging.h>
#include <cpp-utils/process/subprocess.h>
#include <cpp-utils/network/FakeHttpClient.h>
#include "../../cryfs/testutils/MockConsole.h"
#include "../../cryfs/testutils/TestWithFakeHomeDirectory.h"
#include <cryfs/ErrorCodes.h>
#include <cpp-utils/testutils/CaptureStderrRAII.h>
2018-09-07 14:00:47 +02:00
#include <regex>
#include <string>
2015-10-29 19:34:36 +01:00
class CliTest : public ::testing::Test, TestWithFakeHomeDirectory {
2015-10-29 19:34:36 +01:00
public:
CliTest(): _basedir(), _mountdir(), basedir(_basedir.path()), mountdir(_mountdir.path()), logfile(), configfile(false), console(std::make_shared<MockConsole>()) {}
2015-10-29 19:34:36 +01:00
cpputils::TempDir _basedir;
cpputils::TempDir _mountdir;
boost::filesystem::path basedir;
boost::filesystem::path mountdir;
2015-10-29 19:34:36 +01:00
cpputils::TempFile logfile;
cpputils::TempFile configfile;
std::shared_ptr<MockConsole> console;
2015-10-29 19:34:36 +01:00
2017-09-30 23:24:33 +02:00
cpputils::unique_ref<cpputils::HttpClient> _httpClient() {
cpputils::unique_ref<cpputils::FakeHttpClient> httpClient = cpputils::make_unique_ref<cpputils::FakeHttpClient>();
httpClient->addWebsite("https://www.cryfs.org/version_info.json", "{\"version_info\":{\"current\":\"0.8.5\"}}");
return std::move(httpClient);
}
2018-09-07 07:44:23 +02:00
int run(const std::vector<std::string>& args) {
std::vector<const char*> _args;
_args.reserve(args.size() + 1);
_args.emplace_back("cryfs");
for (const std::string& arg : args) {
_args.emplace_back(arg.c_str());
}
auto &keyGenerator = cpputils::Random::PseudoRandom();
2018-09-04 01:51:59 +02:00
ON_CALL(*console, askPassword(testing::StrEq("Password: "))).WillByDefault(testing::Return("pass"));
ON_CALL(*console, askPassword(testing::StrEq("Confirm Password: "))).WillByDefault(testing::Return("pass"));
// Run Cryfs
2018-02-02 01:21:51 +01:00
return cryfs::Cli(keyGenerator, cpputils::SCrypt::TestSettings, console).main(_args.size(), _args.data(), _httpClient());
2015-10-29 19:34:36 +01:00
}
2018-09-07 07:44:23 +02:00
void EXPECT_EXIT_WITH_HELP_MESSAGE(const std::vector<std::string>& args, const std::string &message, cryfs::ErrorCode errorCode) {
EXPECT_RUN_ERROR(args, (".*Usage:.*"+message).c_str(), errorCode);
2015-10-29 19:34:36 +01:00
}
2018-09-07 07:44:23 +02:00
void EXPECT_RUN_ERROR(const std::vector<std::string>& args, const char* message, cryfs::ErrorCode errorCode) {
cpputils::CaptureStderrRAII capturedStderr;
int exit_code = run(args);
capturedStderr.EXPECT_MATCHES(message);
EXPECT_EQ(exitCode(errorCode), exit_code);
2015-10-29 19:34:36 +01:00
}
2018-09-07 07:44:23 +02:00
void EXPECT_RUN_SUCCESS(const std::vector<std::string>& args, const boost::filesystem::path &mountDir) {
//TODO Make this work when run in background
ASSERT(std::find(args.begin(), args.end(), string("-f")) != args.end(), "Currently only works if run in foreground");
bool unmount_success = false;
std::thread unmountThread([&mountDir, &unmount_success] {
auto start = std::chrono::steady_clock::now();
2015-11-02 21:20:10 +01:00
int returncode = -1;
while (returncode != 0) {
if (std::chrono::steady_clock::now() - start > std::chrono::seconds(10)) {
return; // keep unmount_success = false
}
#if defined(__APPLE__)
returncode = cpputils::Subprocess::call(std::string("umount ") + mountDir.string().c_str() + " 2>/dev/null").exitcode;
#elif defined(_MSC_VER)
// Somehow this sleeping is needed to not deadlock. Race condition in mounting/unmounting?
std::this_thread::sleep_for(std::chrono::milliseconds(50));
std::wstring mountDir_ = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>().from_bytes(mountDir.string());
BOOL success = DokanRemoveMountPoint(mountDir_.c_str());
returncode = success ? 0 : -1;
2017-08-24 22:58:41 +02:00
#else
returncode = cpputils::Subprocess::call(std::string("fusermount -u ") + mountDir.string().c_str() + " 2>/dev/null").exitcode;
2017-08-24 22:58:41 +02:00
#endif
2015-11-02 21:20:10 +01:00
}
unmount_success = true;
2015-11-02 21:20:10 +01:00
});
testing::internal::CaptureStdout();
2015-11-02 21:20:10 +01:00
run(args);
std::string _stdout = testing::internal::GetCapturedStdout();
2015-11-02 21:20:10 +01:00
unmountThread.join();
EXPECT_TRUE(unmount_success);
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
// EXPECT_THAT(testing::internal::GetCapturedStdout(), testing::MatchesRegex(".*Mounting filesystem.*"));
EXPECT_TRUE(std::regex_search(_stdout, std::regex(".*Mounting filesystem.*")));
2015-10-29 19:34:36 +01:00
}
};
#endif