mirror of
https://github.com/falk-werner/webfuse
synced 2024-10-27 20:34:10 +00:00
added basic access test
This commit is contained in:
parent
a86061356a
commit
2e3d7a66b5
@ -50,11 +50,14 @@ if(NOT(WITHOUT_TEST))
|
||||
pkg_check_modules(GMOCK REQUIRED gmock)
|
||||
|
||||
add_executable(alltests
|
||||
test-src/webfuse/test/thread.cpp
|
||||
test-src/webfuse/test/tempdir.cpp
|
||||
test-src/webfuse/test/fixture.cpp
|
||||
test-src/webfuse/test/process.cpp
|
||||
test-src/webfuse/test/daemon.cpp
|
||||
test-src/webfuse/test_app.cpp
|
||||
test-src/webfuse/test_request_type.cpp
|
||||
test-src/webfuse/test_response_type.cpp
|
||||
test-src/webfuse/test_access.cpp
|
||||
test-src/webfuse/filesystem/test_status.cpp
|
||||
test-src/webfuse/filesystem/test_accessmode.cpp
|
||||
test-src/webfuse/filesystem/test_openflags.cpp
|
||||
|
@ -34,6 +34,11 @@ public:
|
||||
client.service();
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
client.interrupt();
|
||||
}
|
||||
|
||||
void set_connection_listener(std::function<void(bool)> listener)
|
||||
{
|
||||
client.set_connection_listener(listener);
|
||||
@ -144,6 +149,11 @@ void provider::service()
|
||||
d->service();
|
||||
}
|
||||
|
||||
void provider::interrupt()
|
||||
{
|
||||
d->interrupt();
|
||||
}
|
||||
|
||||
void provider::set_connection_listener(std::function<void(bool)> listener)
|
||||
{
|
||||
d->set_connection_listener(listener);
|
||||
|
@ -20,6 +20,7 @@ public:
|
||||
void set_connection_listener(std::function<void(bool)> listener);
|
||||
void connect(std::string const & url);
|
||||
void service();
|
||||
void interrupt();
|
||||
private:
|
||||
class detail;
|
||||
detail * d;
|
||||
|
@ -34,6 +34,7 @@ extern "C" int webfuse_client_callback(lws * wsi, lws_callback_reasons reason, v
|
||||
context->connection_listener(true);
|
||||
break;
|
||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||
std::cout << "connection error" << std::endl;
|
||||
// fall-through
|
||||
case LWS_CALLBACK_CLIENT_CLOSED:
|
||||
std::cout << "closed" << std::endl;
|
||||
|
37
test-src/webfuse/test/daemon.cpp
Normal file
37
test-src/webfuse/test/daemon.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "webfuse/test/daemon.hpp"
|
||||
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <csignal>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::string get_executable_path()
|
||||
{
|
||||
char directory[PATH_MAX] = { '\0' };
|
||||
readlink("/proc/self/exe", directory, PATH_MAX);
|
||||
dirname(directory);
|
||||
|
||||
return std::string(directory) + "/webfuse";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
daemon::daemon(std::string const & mountpoint)
|
||||
: p({get_executable_path(), "-f", mountpoint})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
daemon::~daemon()
|
||||
{
|
||||
p.kill(SIGINT);
|
||||
}
|
||||
|
||||
}
|
25
test-src/webfuse/test/daemon.hpp
Normal file
25
test-src/webfuse/test/daemon.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef WEBFUSE_DAEMOM_HPP
|
||||
#define WEBFUSE_DAEMOM_HPP
|
||||
|
||||
#include "webfuse/test/process.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
class daemon
|
||||
{
|
||||
daemon(daemon const &) = delete;
|
||||
daemon& operator=(daemon const &) = delete;
|
||||
daemon(daemon &&) = delete;
|
||||
daemon& operator=(daemon &&) = delete;
|
||||
public:
|
||||
explicit daemon(std::string const & mountpoint);
|
||||
~daemon();
|
||||
private:
|
||||
process p;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
47
test-src/webfuse/test/filesystem_mock.hpp
Normal file
47
test-src/webfuse/test/filesystem_mock.hpp
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef WEBFUSE_FILESYSTEM_MOCK_HPP
|
||||
#define WEBFUSE_FILESYSTEM_MOCK_HPP
|
||||
|
||||
#include "webfuse/filesystem/filesystem_i.hpp"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
class filesystem_mock: public filesystem_i
|
||||
{
|
||||
public:
|
||||
~filesystem_mock() override = default;
|
||||
|
||||
MOCK_METHOD(int, access, (std::string const & path, int mode));
|
||||
MOCK_METHOD(int, getattr, (std::string const & path, struct stat * attr));
|
||||
|
||||
MOCK_METHOD(int, readlink, (std::string const & path, std::string & out));
|
||||
MOCK_METHOD(int, symlink, (std::string const & target, std::string const & linkpath));
|
||||
MOCK_METHOD(int, link, (std::string const & old_path, std::string const & new_path));
|
||||
|
||||
MOCK_METHOD(int, rename, (std::string const & old_path, std::string const & new_path, int flags));
|
||||
MOCK_METHOD(int, chmod, (std::string const & path, mode_t mode));
|
||||
MOCK_METHOD(int, chown, (std::string const & path, uid_t uid, gid_t gid));
|
||||
MOCK_METHOD(int, truncate, (std::string const & path, uint64_t size, uint64_t handle));
|
||||
MOCK_METHOD(int, fsync, (std::string const & path, bool is_datasync, uint64_t handle));
|
||||
MOCK_METHOD(int, utimens, (std::string const &path, struct timespec tv[2], uint64_t handle));
|
||||
|
||||
MOCK_METHOD(int, open, (std::string const & path, int flags, uint64_t & handle));
|
||||
MOCK_METHOD(int, mknod, (std::string const & path, mode_t mode, dev_t rdev));
|
||||
MOCK_METHOD(int, create, (std::string const & path, mode_t mode, uint64_t & handle));
|
||||
MOCK_METHOD(int, release, (std::string const & path, uint64_t handle));
|
||||
MOCK_METHOD(int, unlink, (std::string const & path));
|
||||
|
||||
MOCK_METHOD(int, read, (std::string const & path, char * buffer, size_t buffer_size, uint64_t offset, uint64_t handle));
|
||||
MOCK_METHOD(int, write, (std::string const & path, char const * buffer, size_t buffer_size, uint64_t offset, uint64_t handle));
|
||||
|
||||
MOCK_METHOD(int, mkdir, (std::string const & path, mode_t mode));
|
||||
MOCK_METHOD(int, readdir, (std::string const & path, std::vector<std::string> & entries, uint64_t handle));
|
||||
MOCK_METHOD(int, rmdir, (std::string const & path));
|
||||
|
||||
MOCK_METHOD(int, statfs, (std::string const & path, struct statvfs * statistics));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
63
test-src/webfuse/test/fixture.cpp
Normal file
63
test-src/webfuse/test/fixture.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "webfuse/test/fixture.hpp"
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
fixture::fixture(filesystem_i & fs)
|
||||
: shutdown_requested(false)
|
||||
, provider_running(false)
|
||||
, fs_provider(fs)
|
||||
, app(working_dir.name())
|
||||
{
|
||||
fs_provider.set_connection_listener([this](bool is_connected) {
|
||||
if (is_connected)
|
||||
{
|
||||
this->provider_running = true;
|
||||
}
|
||||
|
||||
if ((!is_connected) && (!this->provider_running))
|
||||
{
|
||||
this->reconnect();
|
||||
}
|
||||
});
|
||||
provider_thread = std::thread(std::bind(&fixture::provider_run, this));
|
||||
while (!provider_running)
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
|
||||
fixture::~fixture()
|
||||
{
|
||||
shutdown_requested = true;
|
||||
fs_provider.interrupt();
|
||||
provider_thread.join();
|
||||
}
|
||||
|
||||
void fixture::provider_run()
|
||||
{
|
||||
fs_provider.connect("ws://localhost:8081/");
|
||||
while (!shutdown_requested)
|
||||
{
|
||||
fs_provider.service();
|
||||
}
|
||||
}
|
||||
|
||||
void fixture::reconnect()
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
fs_provider.connect("ws://localhost:8081/");
|
||||
}
|
||||
|
||||
std::string const & fixture::get_path() const
|
||||
{
|
||||
return working_dir.name();
|
||||
}
|
||||
|
||||
|
||||
}
|
46
test-src/webfuse/test/fixture.hpp
Normal file
46
test-src/webfuse/test/fixture.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef WEBFUSE_FIXTURE_HPP
|
||||
#define WEBFUSE_FIXTURE_HPP
|
||||
|
||||
#include "webfuse/filesystem/filesystem_i.hpp"
|
||||
#include "webfuse/webfuse.hpp"
|
||||
#include "webfuse/provider.hpp"
|
||||
|
||||
#include "webfuse/test/tempdir.hpp"
|
||||
#include "webfuse/test/daemon.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
class fixture
|
||||
{
|
||||
fixture(fixture const &) = delete;
|
||||
fixture& operator=(fixture const &) = delete;
|
||||
fixture(fixture const &&) = delete;
|
||||
fixture& operator=(fixture &&) = delete;
|
||||
public:
|
||||
explicit fixture(filesystem_i & fs);
|
||||
~fixture();
|
||||
|
||||
std::string const & get_path() const;
|
||||
|
||||
void reconnect();
|
||||
private:
|
||||
void provider_run();
|
||||
std::atomic<bool> shutdown_requested;
|
||||
std::atomic<bool> provider_running;
|
||||
provider fs_provider;
|
||||
|
||||
tempdir working_dir;
|
||||
daemon app;
|
||||
std::thread provider_thread;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
93
test-src/webfuse/test/process.cpp
Normal file
93
test-src/webfuse/test/process.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "webfuse/test/process.hpp"
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
process::process(std::vector<std::string> const & commandline)
|
||||
{
|
||||
if (commandline.empty())
|
||||
{
|
||||
throw std::runtime_error("missing command");
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0)
|
||||
{
|
||||
size_t const count = commandline.size() + 1;
|
||||
char ** args = reinterpret_cast<char**>(malloc(sizeof(char*) * count));
|
||||
args[count - 1] = nullptr;
|
||||
for(size_t i = 0; i < commandline.size(); i++)
|
||||
{
|
||||
args[i] = strdup(commandline[i].c_str());
|
||||
}
|
||||
|
||||
closefrom(0);
|
||||
open("/dev/null", O_RDONLY);
|
||||
open("/dev/null", O_WRONLY);
|
||||
dup2(STDOUT_FILENO, STDERR_FILENO);
|
||||
|
||||
execv(args[0], args);
|
||||
|
||||
// this should not be reached
|
||||
for(size_t i = 0; i < count; i++)
|
||||
{
|
||||
free(args[i]);
|
||||
}
|
||||
free(args);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (pid > 0)
|
||||
{
|
||||
// parent: do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("failed to fork");
|
||||
}
|
||||
}
|
||||
|
||||
process::~process()
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
wait();
|
||||
}
|
||||
}
|
||||
|
||||
void process::kill(int signal_number)
|
||||
{
|
||||
if (pid > 0)
|
||||
{
|
||||
::kill(pid, signal_number);
|
||||
}
|
||||
}
|
||||
|
||||
int process::wait()
|
||||
{
|
||||
int exit_code = -1;
|
||||
|
||||
if (pid > 0)
|
||||
{
|
||||
int status = 0;
|
||||
int rc = waitpid(pid, &status, 0);
|
||||
if (rc == 0)
|
||||
{
|
||||
exit_code = WEXITSTATUS(status);
|
||||
pid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
}
|
29
test-src/webfuse/test/process.hpp
Normal file
29
test-src/webfuse/test/process.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef WEBFUSE_PROCESS_HPP
|
||||
#define WEBFUSE_PROCESS_HPP
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
class process
|
||||
{
|
||||
process(process const &) = delete;
|
||||
process operator=(process const &) = delete;
|
||||
process(process &&) = delete;
|
||||
process operator=(process &&) = delete;
|
||||
public:
|
||||
process(std::vector<std::string> const & commandline);
|
||||
~process();
|
||||
void kill(int signal_number);
|
||||
int wait();
|
||||
private:
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -15,7 +15,7 @@ tempdir::~tempdir()
|
||||
unlink(path.c_str());
|
||||
}
|
||||
|
||||
std::string const tempdir::name() const
|
||||
std::string const & tempdir::name() const
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ class tempdir
|
||||
public:
|
||||
tempdir();
|
||||
~tempdir();
|
||||
std::string const name() const;
|
||||
std::string const & name() const;
|
||||
private:
|
||||
std::string path;
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
#include "webfuse/test/thread.hpp"
|
||||
#include <csignal>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
extern "C" void * webfuse_thread_main(void * args)
|
||||
{
|
||||
auto * run = reinterpret_cast<std::function<void(void)> *>(args);
|
||||
(*run)();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
thread::thread(std::function<void(void)> run)
|
||||
{
|
||||
pthread_create(&real_thread, nullptr,
|
||||
&webfuse_thread_main,
|
||||
reinterpret_cast<void*>(&run));
|
||||
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
pthread_join(real_thread, nullptr);
|
||||
}
|
||||
|
||||
void thread::kill(int signal_id)
|
||||
{
|
||||
pthread_kill(real_thread, signal_id);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
#ifndef WEBFUSE_THREAD_HPP
|
||||
#define WEBFUSE_THREAD_HPP
|
||||
|
||||
#include <pthread.h>
|
||||
#include <functional>
|
||||
|
||||
namespace webfuse
|
||||
{
|
||||
|
||||
class thread
|
||||
{
|
||||
public:
|
||||
explicit thread(std::function<void(void)> run);
|
||||
~thread();
|
||||
void kill(int signal_id);
|
||||
private:
|
||||
pthread_t real_thread;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
45
test-src/webfuse/test_access.cpp
Normal file
45
test-src/webfuse/test_access.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "webfuse/webfuse.hpp"
|
||||
#include "webfuse/test/fixture.hpp"
|
||||
#include "webfuse/test/filesystem_mock.hpp"
|
||||
#include "webfuse/test/daemon.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using testing::_;
|
||||
using testing::Return;
|
||||
using testing::Invoke;
|
||||
using testing::AnyNumber;
|
||||
|
||||
namespace
|
||||
{
|
||||
int fs_getattr (std::string const & path, struct stat * attr)
|
||||
{
|
||||
memset(reinterpret_cast<void*>(attr),0, sizeof(struct stat));
|
||||
|
||||
if (path == "/foo")
|
||||
{
|
||||
attr->st_nlink = 0;
|
||||
attr->st_mode = S_IFREG | 0755;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(access, ok)
|
||||
{
|
||||
webfuse::filesystem_mock fs;
|
||||
webfuse::fixture fixture(fs);
|
||||
std::cout << "setup" << std::endl;
|
||||
|
||||
EXPECT_CALL(fs, access("/foo",_)).WillOnce(Return(0));
|
||||
EXPECT_CALL(fs, getattr(_,_)).WillRepeatedly(Invoke(fs_getattr));
|
||||
auto const path = fixture.get_path() + "/foo";
|
||||
|
||||
int const rc = ::access(path.c_str(), F_OK);
|
||||
ASSERT_EQ(0, rc);
|
||||
}
|
@ -1,38 +1,7 @@
|
||||
#include "webfuse/webfuse.hpp"
|
||||
#include "webfuse/test/thread.hpp"
|
||||
#include "webfuse/test/tempdir.hpp"
|
||||
#include <gtest/gtest.h>
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
extern "C" void * run(void * args)
|
||||
{
|
||||
webfuse::app * app = reinterpret_cast<webfuse::app*>(args);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TEST(app, init)
|
||||
{
|
||||
webfuse::app app;
|
||||
}
|
||||
|
||||
TEST(app, run)
|
||||
{
|
||||
webfuse::tempdir dir;
|
||||
webfuse::thread thread([&dir](){
|
||||
webfuse::app app;
|
||||
char arg0[] = "webfuse";
|
||||
char arg1[] = "-f";
|
||||
char* arg2 = strdup(dir.name().c_str());
|
||||
char* argv[] = { arg0, arg1, arg2, nullptr};
|
||||
int rc = app.run(3, argv);
|
||||
free(arg2);
|
||||
});
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
thread.kill(SIGINT);
|
||||
}
|
Loading…
Reference in New Issue
Block a user