1
0
mirror of https://github.com/falk-werner/webfused synced 2024-10-27 20:44:08 +00:00

Merge pull request #1 from falk-werner/config_file

feature: provide settings in a config file
This commit is contained in:
Falk Werner 2020-03-18 19:41:50 +01:00 committed by GitHub
commit d252fd7411
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 4266 additions and 205 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
/build/
/.deps/
/.deps/
/.vscode/

View File

@ -24,7 +24,16 @@ addons:
- python3-setuptools
- python3-wheel
- ninja-build
- libconfig-dev
- valgrind
env:
matrix:
- BUILD_TYPE=Coverage CHECK_TARGET=check
- BUILD_TYPE=Debug CHECK_TARGET=memcheck
- BUILD_TPYE=Release CHECK_TARGET=check
- BUILD_TYPE=MinSizeRel CHECK_TARGET=check
before_install:
- mkdir .deps
@ -74,12 +83,27 @@ before_install:
- sudo make install
- cd ..
- cd ..
# gtest
- wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz
- tar -xf release-1.10.0.tar.gz
- cd googletest-release-1.10.0
- mkdir .build
- cd .build
- cmake ..
- make
- sudo make install
- cd ..
- cd ..
- cd ..
before_script:
- mkdir build
- cd build
- cmake ..
- cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE ..
script:
make
- export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib:/usr/local/lib/x86_64-linux-gnu"
- make $CHECK_TARGET
after_success:
- bash <(curl -s https://codecov.io/bash)

View File

@ -1,6 +1,8 @@
cmake_minimum_required (VERSION 3.10)
project(webfused VERSION 0.1.0 DESCRIPTION "Webfuse daemon")
option(WITHOUT_TESTS "disable unit tests" OFF)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
@ -9,6 +11,7 @@ pkg_check_modules(FUSE3 REQUIRED fuse3)
pkg_check_modules(LWS REQUIRED libwebsockets)
pkg_check_modules(JANSSON REQUIRED jansson)
pkg_check_modules(UUID REQUIRED uuid)
pkg_check_modules(LIBCONFIG REQUIRED libconfig)
pkg_check_modules(OPENSSL REQUIRED openssl)
pkg_check_modules(WEBFUSE REQUIRED libwebfuse-adapter)
@ -30,24 +33,46 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(C_WARNINGS -Wall -Wextra)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(coverage)
add_library(userdb STATIC
src/userdb/userdb.c
)
target_include_directories(userdb PUBLIC
${LIBCONFIG_INCLUDE_DIRS}
${OPENSSL_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
)
target_compile_options(userdb PUBLIC ${OPENSSL_CFLAGS_OTHER})
add_executable(webfused
src/daemon/main.c
add_library(webfused-static STATIC
src/webfused/daemon.c
src/webfused/mountpoint_factory.c
src/webfused/config/config.c
src/webfused/config/factory.c
src/webfused/config/builder.c
src/webfused/config/settings.c
src/webfused/auth/authenticator.c
src/webfused/auth/factory.c
src/webfused/auth/file_authenticator.c
src/webfused/log/log.c
src/webfused/log/logger.c
src/webfused/log/manager.c
src/webfused/log/stderr_logger.c
src/webfused/log/syslog_logger.c
)
target_link_libraries(webfused PUBLIC
add_executable(webfused
src/webfused/main.c
)
target_link_libraries(webfused PUBLIC
webfused-static
userdb
${LIBCONFIG_LIBRARIES}
${OPENSSL_LIBRARIES}
${WEBFUSE_LIBRARIES}
${UUID_LIBRARIES}
@ -75,3 +100,95 @@ target_include_directories(webfuse-passwd PUBLIC
target_compile_options(webfuse-passwd PUBLIC ${OPENSSL_CFLAGS_OTHER})
install(TARGETS webfuse-passwd DESTINATION bin)
if(NOT WITHOUT_TESTS)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
include (CTest)
pkg_check_modules(GTEST gtest_main)
include(GoogleTest)
pkg_check_modules(GMOCK gmock)
add_executable(alltests
test/mock_config_builder.cc
test/mock_logger.cc
test/mock_credentials.cc
test/mock_settings.cc
test/test_config_factory.cc
test/test_config.cc
test/test_settings.cc
test/test_auth_factory.cc
test/test_file_authenticator.cc
test/test_mountpoint_factory.cc
test/test_log.cc
test/test_log_manager.cc
test/test_stderr_logger.cc
test/test_syslog_logger.cc
test/test_daemon.cc
)
target_include_directories(alltests PRIVATE
src
${GMOCK_INCLUDE_DIRS}
${GTEST_INCLUDE_DIRS}
)
target_compile_options(alltests PRIVATE ${GMOCK_CFLAGS} ${GTEST_CFLAGS} "-pthread")
target_link_libraries(alltests PRIVATE
-Wl,--wrap=wf_credentials_type
-Wl,--wrap=wf_credentials_get
-Wl,--wrap=wfd_settings_get_string
-Wl,--wrap=wfd_settings_get_string_or_default
-Wl,--wrap=wfd_settings_get_bool
webfused-static
userdb
${LIBCONFIG_LIBRARIES}
${WEBFUSE_LIBRARIES}
${UUID_LIBRARIES}
${OPENSSL_LIBRARIES}
${GMOCK_LIBRARIES}
${GTEST_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
# copy test data
configure_file(etc/webfused.conf webfused.conf COPYONLY)
configure_file(test/invalid.conf invalid.conf COPYONLY)
configure_file(test/test_passwd.json test_passwd.json COPYONLY)
enable_testing()
gtest_discover_tests(alltests TEST_PREFIX alltests:)
add_custom_target(check
./alltests)
add_dependencies(check alltests)
add_custom_target(memcheck
valgrind ./alltests)
add_dependencies(memcheck alltests)
add_custom_target(coverage
mkdir -p coverage
COMMAND lcov --initial --capture --directory . --output-file coverage/lcov_base.info --rc lcov_branch_coverage=1
COMMAND ./alltests
COMMAND lcov --capture --directory . --output-file coverage/lcov.info --rc lcov_branch_coverage=1
COMMAND lcov -a coverage/lcov_base.info -a coverage/lcov.info --output-file coverage/lcov.info --rc lcov_branch_coverage=1
COMMAND lcov --remove coverage/lcov.info '/usr/*' --output-file coverage/lcov.info --rc lcov_branch_coverage=1
COMMAND lcov --remove coverage/lcov.info '*/test/*' --output-file coverage/lcov.info --rc lcov_branch_coverage=1
COMMAND lcov --remove coverage/lcov.info '*/main.c' --output-file coverage/lcov.info --rc lcov_branch_coverage=1
)
add_dependencies(coverage alltests)
add_custom_target(coverage-report
COMMAND genhtml --branch-coverage --highlight --legend coverage/lcov.info --output-directory coverage/report
)
add_dependencies(coverage-report coverage)
endif(NOT WITHOUT_TESTS)

162
README.md
View File

@ -1,4 +1,5 @@
[![Build Status](https://travis-ci.org/falk-werner/webfused.svg?branch=master)](https://travis-ci.org/falk-werner/webfused)
[![codecov](https://codecov.io/gh/falk-werner/webfused/branch/config_file/graph/badge.svg)](https://codecov.io/gh/falk-werner/webfused)
# webfused
@ -13,7 +14,145 @@ To install dependecies, see below.
cd build
cmake ..
make
./webfused -m test --port=4711
./webfused -f webfused.conf
## Config file
```
version = { major = 1, minor = 0 }
server:
{
vhost_name = "localhost"
port = 8080
tls:
{
certificate = "/etc/webfused/cert.pem"
key = "/etc/webfused/key.pem"
}
document_root = "/var/www"
}
authentication:
(
{
provider = "file"
settings:
{
file = "/etc/webfused/passwd"
}
}
)
filesystems:
(
{name = "test", mount_point = "/tmp/webfused" }
)
log:
{
provider: "syslog"
level: "warning"
settings:
{
ident = "webfused"
facility = "daemon"
log_pid = true
}
}
```
### Version
The version sections specifies the schema version of the config file.
Currently, there is only one schema version defined: 1.0
### Server
| Setting | Type | Default value | Description |
| ------------- | ------ | ------------- | ------------------------ |
| vhostname | string | localhost | Name of the virtual host |
| port | int | 8080 | Port number of server |
| document_root | string | *-empty-* | Path of HTTP files |
| tls | object | *-empty-* | see below |
When *document_root* is omitted, no HTTP files are served.
#### TLS
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | ------------------------------------------- |
| certificate | string | *-empty-* | Path to servers own certificate (.pem file) |
| key | string | *-empty-* | Path to servers own private key (.pem file) |
TLS is only activated, when both, *certificate* and *key* are specified.
Otherwise, plain websockes without TLS are used.
### Authentication
| Setting | Type | Default value | Description |
| -------- | ------ | ------------- | ----------------------------------------------- |
| provider | string | *-required-* | Name of the authentication provider (see below) |
| settings | object | *-empty-* | Provider specific settings (see below)
Currently, only one provider is specified:
- *file*: file based authentication
### File Authenticaton Provider
Allows authentication against a file containing username and password.
| Setting | Type | Default value | Description |
| -------- | ------ | ------------- | ------------------------------- |
| file | string | *-empty-* | Path to the authentication file |
### Filesystems
Contains a list of file systems that can be provided by webfuse providers.
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | ---------------------------------- |
| name | string | *-required-* | Name of the filesystem |
| mount_point | string | *-required-* | Local path to mount the filesystem |
### Log
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | -------------------------------------- |
| provider | string | *-required-* | Name of log provider (see below) |
| level | string | *-required-* | Log level (see below) |
| settings | object | *-empty-* | Provider specific settings (see below) |
The following log levels are supported:
- *none*: diabled logging
- *fatal*: log only fatal errors
- *error*: log all kind of errors
- *warn*: log errors and warnings
- *info*: log info messages, warnings and errors
- *debug*: log debug and info messages as well as warnings and errors
- *all*: log all kind of messages
Currently, the following providers are available:
- *stderr*: logs to console error output
- *syslog*: logs to syslog
#### Stderr Logger
This logger does not provide any settings.
#### Syslog Logger
| Setting | Type | Default value | Description |
| ----------- | ------ | ------------- | ------------------------------------------ |
| ident | string | webfused | Syslog ident (see syslog documentation) |
| facility | string | daemon | Syslog facility (see syslog documentation) |
| log_pid | bool | false | Add process ID to log messages |
## Dependencies
@ -22,6 +161,8 @@ To install dependecies, see below.
- [libwebsockets](https://libwebsockets.org/)
- [jansson](https://github.com/akheron/jansson)
- [openssl](https://www.openssl.org/)
- [libconfig](https://hyperrealm.github.io/libconfig/)
- [Google Test](https://github.com/google/googletest) *(Test only)*
### Installing dependencies
@ -49,7 +190,6 @@ To install libfuse, meson is needed. Please refer to [meson quick guide](https:/
make
sudo make install
#### jansson
wget https://github.com/akheron/jansson/archive/v2.12.tar.gz -O jansson.tar.gz
@ -76,3 +216,21 @@ To install libfuse, meson is needed. Please refer to [meson quick guide](https:/
cmake -DWITHOUT_TESTS=ON ..
make
sudo make install
#### libconfig
sudo apt update
sudo apt install libconfig-dev
#### GoogleTest
Installation of GoogleTest is optional webfuse library, but required to compile tests.
wget -O gtest-1.10.0.tar.gz https://github.com/google/googletest/archive/release-1.10.0.tar.gz
tar -xf gtest-1.10.0.tar.gz
cd googletest-release-1.10.0
mkdir .build
cd .build
cmake ..
make
sudo make install

30
cmake/coverage.cmake Normal file
View File

@ -0,0 +1,30 @@
set(CMAKE_C_FLAGS_COVERAGE
"${CMAKE_C_FLAGS_DEBUG} -pg --coverage -fprofile-arcs -ftest-coverage"
CACHE STRING "Flags used by the C compiler during coverage builds"
FORCE
)
set(CMAKE_CXX_FLAGS_COVERAGE
"${CMAKE_CXX_FLAGS_DEBUG} -pg --coverage -fprofile-arcs -ftest-coverage"
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE
)
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE
)
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE
)
mark_as_advanced(
CMAKE_C_FLAGS_COVERAGE
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)

2
codecov.yml Normal file
View File

@ -0,0 +1,2 @@
ignore:
- "test/**/*"

45
etc/webfused.conf Normal file
View File

@ -0,0 +1,45 @@
# Webfuse deamon configuration file
version = { major = 1, minor = 0 }
server:
{
vhost_name = "localhost"
port = 8080
# tls:
# {
# certificate = "/etc/webfused/cert.pem"
# key = "/etc/webfused/key.pem"
# }
# document_root = "/var/www"
}
authentication:
(
{
provider = "file"
settings:
{
file = "/etc/webfused/passwd"
}
}
)
filesystems:
(
{name = "test", mount_point = "/tmp/webfused" }
)
log:
{
provider: "syslog"
level: "warning"
settings:
{
ident = "webfused"
facility = "daemon"
log_pid = true
}
}

View File

@ -1,196 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <webfuse_adapter.h>
#include <userdb/userdb.h>
#define SERVICE_TIMEOUT (1 * 1000)
struct args
{
struct wf_server_config * config;
char * passwd_path;
bool show_help;
};
static bool shutdown_requested = false;
static void show_help(void)
{
printf(
"webfused, Copyright (c) 2019, webfused authors <https://github.com/falk-werner/webfused>\n"
"Websocket file system daemon\n"
"\n"
"Usage: webfused [m <mount_point>] [-d <document_root] [-n <vhost_name>] [-p <port>]\n"
" [-c <server_cert_path>] [-k <server_key_path>] [-P <passwd_path>]\n"
"\n"
"Options:\n"
"\t-m, --mount_point Path of mount point (required)\n"
"\t-d, --document_root Path of www directory (default: not set, www disabled)\n"
"\t-c, --server_cert_path Path of servers own certificate (default: not set, TLS disabled)\n"
"\t-k, --server_key_path Path of servers private key (default: not set, TLS disabled)\n"
"\t-n, --vhost_name Name of virtual host (default: \"localhost\")\n"
"\t-p, --port Number of servers port (default: 8080)\n"
"\t-P, --passwd_path Path to password file (default: not set, authentication disabled)\n"
"\n");
}
static bool authenticate(struct wf_credentials * creds, void * user_data)
{
bool result = false;
struct args * args = user_data;
char const * username = wf_credentials_get(creds, "username");
char const * password = wf_credentials_get(creds, "password");
if ((NULL != username) && (NULL != password))
{
struct userdb * db = userdb_create("");
result = userdb_load(db, args->passwd_path);
if (result)
{
result = userdb_check(db, username, password);
}
userdb_dispose(db);
}
return result;
}
static int parse_arguments(int argc, char * argv[], struct args * args)
{
static struct option const options[] =
{
{"mount_point", required_argument, NULL, 'm'},
{"document_root", required_argument, NULL, 'd'},
{"server_cert_path", required_argument, NULL, 'c'},
{"server_key_path", required_argument, NULL, 'k'},
{"vhost_name", required_argument, NULL, 'n'},
{"port", required_argument, NULL, 'p'},
{"passwd_path", required_argument, NULL, 'P'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
bool result = EXIT_SUCCESS;
bool finished = false;
bool has_mountpoint = false;
while ((!finished) && (EXIT_SUCCESS == result))
{
int option_index = 0;
int const c = getopt_long(argc, argv, "m:d:c:k:n:p:P:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
args->show_help = true;
finished = true;
break;
case 'm':
wf_server_config_set_mountpoint(args->config, optarg);
has_mountpoint = true;
break;
case 'd':
wf_server_config_set_documentroot(args->config, optarg);
break;
case 'c':
wf_server_config_set_certpath(args->config, optarg);
break;
case 'k':
wf_server_config_set_keypath(args->config, optarg);
break;
case 'n':
wf_server_config_set_vhostname(args->config, optarg);
break;
case 'p':
wf_server_config_set_port(args->config, atoi(optarg));
break;
case 'P':
free(args->passwd_path);
args->passwd_path = strdup(optarg);
wf_server_config_add_authenticator(args->config,
"username",
&authenticate,
args);
break;
default:
fprintf(stderr, "error: unknown argument\n");
result = EXIT_FAILURE;
break;
}
}
if ((EXIT_SUCCESS == result) && (!args->show_help))
{
if (!has_mountpoint)
{
fprintf(stderr, "error: missing mount point\n");
result = EXIT_FAILURE;
}
}
if (EXIT_SUCCESS != result)
{
args->show_help = true;
}
return result;
}
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
int main(int argc, char * argv[])
{
struct args args;
args.config = wf_server_config_create();
wf_server_config_set_vhostname(args.config, "localhost");
wf_server_config_set_port(args.config, 8080);
args.passwd_path = NULL;
args.show_help = false;
int result = parse_arguments(argc, argv, &args);
if (!args.show_help)
{
signal(SIGINT, on_interrupt);
struct wf_server * server = wf_server_create(args.config);
if (NULL != server)
{
while (!shutdown_requested)
{
wf_server_service(server, SERVICE_TIMEOUT);
}
wf_server_dispose(server);
}
else
{
fprintf(stderr, "fatal: unable start server\n");
result = EXIT_FAILURE;
}
}
else
{
show_help();
}
free(args.passwd_path);
wf_server_config_dispose(args.config);
return result;
}

View File

@ -0,0 +1,24 @@
#include "webfused/auth/authenticator.h"
void
wfd_authenticator_dispose(
struct wfd_authenticator authenticator)
{
authenticator.vtable->dispose(authenticator.data);
}
extern bool
wfd_authenticator_authenticate(
struct wfd_authenticator authenticator,
struct wf_credentials * credentials)
{
return authenticator.vtable->authenticate(
credentials, authenticator.data);
}
char const *
wfd_authenticator_get_type(
struct wfd_authenticator authenticator)
{
return authenticator.vtable->get_type(authenticator.data);
}

View File

@ -0,0 +1,49 @@
#ifndef WFD_AUTH_AUTHENTICATOR_H
#define WFD_AUTH_AUTHENTICATOR_H
#include "webfuse/adapter/authenticate.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef void
wfd_authenticator_dispose_fn(
void * data);
typedef char const *
wfd_authenticator_get_type_fn(
void * data);
struct wfd_authenticator_vtable
{
wfd_authenticator_dispose_fn * dispose;
wf_authenticate_fn * authenticate;
wfd_authenticator_get_type_fn * get_type;
};
struct wfd_authenticator
{
struct wfd_authenticator_vtable const * vtable;
void * data;
};
extern void
wfd_authenticator_dispose(
struct wfd_authenticator authenticator);
extern bool
wfd_authenticator_authenticate(
struct wfd_authenticator authenticator,
struct wf_credentials * credentials);
extern char const *
wfd_authenticator_get_type(
struct wfd_authenticator authenticator);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,25 @@
#include "webfused/auth/factory.h"
#include "webfused/auth/file_authenticator.h"
#include "webfused/config/settings.h"
#include "webfused/log/log.h"
#include <string.h>
bool
wfd_authenticator_create(
char const * provider,
struct wfd_settings * settings,
struct wfd_authenticator * authenticator)
{
bool result = false;
if (0 == strcmp("file", provider))
{
result = wfd_file_authenticator_create(settings, authenticator);
}
else
{
WFD_ERROR("failed to create authenticator: unknown type \"%s\"", provider);
}
return result;
}

View File

@ -0,0 +1,26 @@
#ifndef WFD_AUTHENTICATION_FACTORY_H
#define WFD_AUTHENTICATION_FACTORY_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_authenticator;
struct wfd_settings;
extern bool
wfd_authenticator_create(
char const * provider,
struct wfd_settings * settings,
struct wfd_authenticator * authenticator);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,91 @@
#include "webfused/auth/file_authenticator.h"
#include "webfused/auth/authenticator.h"
#include "webfused/config/settings.h"
#include "userdb/userdb.h"
#include "webfused/log/log.h"
#include <webfuse/adapter/credentials.h>
#include <stdlib.h>
#include <string.h>
struct wfd_file_authenticator
{
char * filename;
};
static void
wfd_file_authenticator_dispose(
void * data)
{
struct wfd_file_authenticator * authenticator = data;
free(authenticator->filename);
free(authenticator);
}
static bool
wfd_file_authenticator_authenticate(
struct wf_credentials * credentials,
void * user_data)
{
bool result = false;
struct wfd_file_authenticator * authenticator = user_data;
char const * username = wf_credentials_get(credentials, "username");
char const * password = wf_credentials_get(credentials, "password");
if ((NULL != username) && (NULL != password))
{
struct userdb * db = userdb_create("");
result = userdb_load(db, authenticator->filename);
if (result)
{
result = userdb_check(db, username, password);
}
userdb_dispose(db);
}
WFD_INFO("authenticate user \'%s\': %s",
(NULL != username) ? username : "<unknown>",
result ? "success" : "failure");
return result;
}
static char const *
wfd_file_authenticator_get_type(
void * data)
{
(void) data;
return "username";
}
static struct wfd_authenticator_vtable
wfd_file_authenticator_vtable =
{
.dispose = &wfd_file_authenticator_dispose,
.authenticate = &wfd_file_authenticator_authenticate,
.get_type = &wfd_file_authenticator_get_type
};
bool
wfd_file_authenticator_create(
struct wfd_settings * settings,
struct wfd_authenticator * authenticator)
{
bool result = false;
char const * filename = wfd_settings_get_string(settings, "file");
if (NULL != filename)
{
struct wfd_file_authenticator * data = malloc(sizeof(struct wfd_file_authenticator));
data->filename = strdup(filename);
authenticator->vtable = &wfd_file_authenticator_vtable;
authenticator->data = data;
result = true;
}
return result;
}

View File

@ -0,0 +1,26 @@
#ifndef WFD_AUTH_FILE_AUTHENTICATOR_H
#define WFD_AUTH_FILE_AUTHENTICATOR_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_authenticator;
struct wfd_settings;
extern bool
wfd_file_authenticator_create(
struct wfd_settings * settings,
struct wfd_authenticator * authenticator);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,72 @@
#include "webfused/config/builder.h"
void
wfd_config_builder_set_server_vhostname(
struct wfd_config_builder builder,
char const * vhost_name)
{
builder.vtable->set_server_vhostname(builder.data, vhost_name);
}
void
wfd_config_builder_set_server_port(
struct wfd_config_builder builder,
int port)
{
builder.vtable->set_server_port(builder.data, port);
}
void
wfd_config_builder_set_server_key(
struct wfd_config_builder builder,
char const * key_path)
{
builder.vtable->set_server_key(builder.data, key_path);
}
void
wfd_config_builder_set_server_cert(
struct wfd_config_builder builder,
char const * cert_path)
{
builder.vtable->set_server_cert(builder.data, cert_path);
}
void
wfd_config_builder_set_server_document_root(
struct wfd_config_builder builder,
char const * document_root)
{
builder.vtable->set_server_document_root(builder.data, document_root);
}
bool
wfd_config_builder_add_auth_provider(
struct wfd_config_builder builder,
char const * provider,
struct wfd_settings * settings)
{
return builder.vtable->add_auth_provider(builder.data, provider, settings);
}
bool
wfd_config_builder_add_filesystem(
struct wfd_config_builder builder,
char const * name,
char const * mount_point)
{
return builder.vtable->add_filesystem(builder.data, name, mount_point);
}
bool
wfd_config_builder_set_logger(
struct wfd_config_builder builder,
char const * provider,
int level,
struct wfd_settings * settings)
{
return builder.vtable->set_logger(builder.data, provider, level, settings);
}

View File

@ -0,0 +1,125 @@
#ifndef WFD_CONFIG_BUILDER_H
#define WFD_CONFIG_BUILDER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
typedef void
wfd_config_builder_set_server_vhostname_fn(
void * data,
char const * vhost_name);
typedef void
wfd_config_builder_set_server_port_fn(
void * data,
int port);
typedef void
wfd_config_builder_set_server_key_fn(
void * data,
char const * key_path);
typedef void
wfd_config_builder_set_server_cert_fn(
void * data,
char const * cert_path);
typedef void
wfd_config_builder_set_server_document_root_fn(
void * data,
char const * document_root);
typedef bool
wfd_config_builder_add_auth_provider_fn(
void * data,
char const * provider,
struct wfd_settings * settings);
typedef bool
wfd_config_builder_add_filesystem_fn(
void * data,
char const * name,
char const * mount_point);
typedef bool
wfd_config_builder_set_logger_fn(
void * data,
char const * provider,
int level,
struct wfd_settings * settings);
struct wfd_config_builder_vtable
{
wfd_config_builder_set_server_vhostname_fn * set_server_vhostname;
wfd_config_builder_set_server_port_fn * set_server_port;
wfd_config_builder_set_server_key_fn * set_server_key;
wfd_config_builder_set_server_cert_fn * set_server_cert;
wfd_config_builder_set_server_document_root_fn * set_server_document_root;
wfd_config_builder_add_auth_provider_fn * add_auth_provider;
wfd_config_builder_add_filesystem_fn * add_filesystem;
wfd_config_builder_set_logger_fn * set_logger;
};
struct wfd_config_builder
{
struct wfd_config_builder_vtable const * vtable;
void * data;
};
extern void
wfd_config_builder_set_server_vhostname(
struct wfd_config_builder builder,
char const * vhost_name);
extern void
wfd_config_builder_set_server_port(
struct wfd_config_builder builder,
int port);
extern void
wfd_config_builder_set_server_key(
struct wfd_config_builder builder,
char const * key_path);
extern void
wfd_config_builder_set_server_cert(
struct wfd_config_builder builder,
char const * cert_path);
extern void
wfd_config_builder_set_server_document_root(
struct wfd_config_builder builder,
char const * document_root);
extern bool
wfd_config_builder_add_auth_provider(
struct wfd_config_builder builder,
char const * provider,
struct wfd_settings * settings);
extern bool
wfd_config_builder_add_filesystem(
struct wfd_config_builder builder,
char const * name,
char const * mount_point);
extern bool
wfd_config_builder_set_logger(
struct wfd_config_builder builder,
char const * provider,
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,178 @@
#include "webfused/config/config.h"
#include "webfuse/adapter/server_config.h"
#include "webfused/auth/factory.h"
#include "webfused/auth/authenticator.h"
#include "webfused/mountpoint_factory.h"
#include "webfused/log/manager.h"
#include <stdlib.h>
#define WFD_CONFIG_DEFAULT_PORT (8080)
#define WFD_CONFIG_DEFAULT_VHOSTNAME ("localhost")
struct wfd_config
{
struct wf_server_config * server;
bool has_authenticator;
struct wfd_authenticator authenticator;
struct wfd_mountpoint_factory * mountpoint_factory;
};
static void
wfd_config_set_server_vhostname(
void * data,
char const * vhost_name)
{
struct wfd_config * config = data;
wf_server_config_set_vhostname(config->server, vhost_name);
}
static void
wfd_config_set_server_port(
void * data,
int port)
{
struct wfd_config * config = data;
wf_server_config_set_port(config->server, port);
}
static void
wfd_config_set_server_key(
void * data,
char const * key_path)
{
struct wfd_config * config = data;
wf_server_config_set_keypath(config->server, key_path);
}
static void
wfd_config_set_server_cert(
void * data,
char const * cert_path)
{
struct wfd_config * config = data;
wf_server_config_set_certpath(config->server, cert_path);
}
static void
wfd_config_set_server_document_root(
void * data,
char const * document_root)
{
struct wfd_config * config = data;
wf_server_config_set_documentroot(config->server, document_root);
}
static bool
wfd_config_add_auth_provider(
void * data,
char const * provider,
struct wfd_settings * settings)
{
bool result = false;
struct wfd_config * config = data;
if (!config->has_authenticator)
{
result = wfd_authenticator_create(provider, settings, &config->authenticator);
if (result)
{
wf_server_config_add_authenticator(
config->server,
wfd_authenticator_get_type(config->authenticator),
config->authenticator.vtable->authenticate,
config->authenticator.data);
config->has_authenticator = true;
}
}
return result;
}
static bool
wfd_config_add_filesystem(
void * data,
char const * name,
char const * mount_point)
{
struct wfd_config * config = data;
return wfd_mountpoint_factory_add_filesystem(
config->mountpoint_factory, name, mount_point);
}
static bool
wfd_config_set_logger(
void * data,
char const * provider,
int level,
struct wfd_settings * settings)
{
struct wfd_config * config = data;
return wfd_log_manager_set_logger(provider, level, settings);
}
static const struct wfd_config_builder_vtable
wfd_config_vtable_config_builder =
{
.set_server_vhostname = &wfd_config_set_server_vhostname,
.set_server_port = &wfd_config_set_server_port,
.set_server_key = &wfd_config_set_server_key,
.set_server_cert = &wfd_config_set_server_cert,
.set_server_document_root = &wfd_config_set_server_document_root,
.add_auth_provider = &wfd_config_add_auth_provider,
.add_filesystem = &wfd_config_add_filesystem,
.set_logger = &wfd_config_set_logger
};
struct wfd_config *
wfd_config_create(void)
{
struct wfd_config * config = malloc(sizeof(struct wfd_config));
config->mountpoint_factory = wfd_mountpoint_factory_create();
config->has_authenticator = false;
config->server = wf_server_config_create();
wf_server_config_set_vhostname(config->server, WFD_CONFIG_DEFAULT_VHOSTNAME);
wf_server_config_set_port(config->server, WFD_CONFIG_DEFAULT_PORT);
wf_server_config_set_mountpoint_factory(config->server,
wfd_mountpoint_factory_create_mountpoint,
config->mountpoint_factory);
return config;
}
void
wfd_config_dispose(
struct wfd_config * config)
{
wf_server_config_dispose(config->server);
if (config->has_authenticator)
{
wfd_authenticator_dispose(config->authenticator);
}
wfd_mountpoint_factory_dispose(config->mountpoint_factory);
free(config);
}
struct wfd_config_builder
wfd_config_get_builder(
struct wfd_config * config)
{
struct wfd_config_builder builder =
{
&wfd_config_vtable_config_builder,
config
};
return builder;
}
struct wf_server_config *
wfd_config_get_server_config(
struct wfd_config * config)
{
return config->server;
}

View File

@ -0,0 +1,40 @@
#ifndef WFD_CONFIG_H
#define WFD_CONFIG_H
#include "webfused/config/builder.h"
#ifndef __cplusplus
#include <stdbool.h>
#include <stddef.h>
#else
#include <cstddef>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_config;
struct wf_server_config;
extern struct wfd_config *
wfd_config_create(void);
extern void
wfd_config_dispose(
struct wfd_config * config);
extern struct wfd_config_builder
wfd_config_get_builder(
struct wfd_config * config);
extern struct wf_server_config *
wfd_config_get_server_config(
struct wfd_config * config);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,332 @@
#include "webfused/config/factory.h"
#include "webfused/config/settings_intern.h"
#include "webfused/log/log.h"
#include <libconfig.h>
#include <stdlib.h>
#include <stdbool.h>
#if ((LIBCONFIG_VER_MAJOR != 1) || (LIBCONFIG_VER_MINOR < 5))
#error "linconfig 1.5 or higher needed"
#endif
#define WFD_CONFIG_VERSION_MAJOR 1
#define WFD_CONFIG_VERSION_MINOR 0
static bool
wfd_config_check_version(
config_t * config)
{
int version_major;
int rc = config_lookup_int(config, "version.major", &version_major);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing version.major");
return false;
}
if (WFD_CONFIG_VERSION_MAJOR != version_major)
{
WFD_ERROR("failed to load config: "
"incompatible versions: expected %d, but war %d",
WFD_CONFIG_VERSION_MAJOR, version_major);
return false;
}
int version_minor;
rc = config_lookup_int(config, "version.minor", &version_minor);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("failed to load config: missing version.minor");
return false;
}
if (WFD_CONFIG_VERSION_MINOR < version_minor)
{
WFD_WARN("newer config detected: some features might be disabled");
}
else if (WFD_CONFIG_VERSION_MINOR > version_minor)
{
WFD_INFO("old config detected: some features might use default values");
}
return true;
}
static bool
wfd_config_read_logger(
config_t * config,
struct wfd_config_builder builder)
{
bool result = true;
bool hasLogger = (NULL != config_lookup(config, "log"));
if (hasLogger)
{
char const * provider;
int rc = config_lookup_string(config, "log.provider", &provider);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("missing log provider");
result = false;
}
char const * level_str;
if (result)
{
rc = config_lookup_string(config, "log.level", &level_str);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("missing log level");
result = false;
}
}
int level;
if (result)
{
bool success = wfd_log_level_parse(level_str, &level);
if (!success)
{
WFD_ERROR("failed to parse log level: unknown valuie \'%s\'", level_str);
result = false;
}
}
if (result)
{
config_setting_t * setting = config_lookup(config, "log.settings");
struct wfd_settings settings;
wfd_settings_init(&settings, setting);
result = wfd_config_builder_set_logger(builder, provider, level, &settings);
wfd_settings_cleanup(&settings);
}
}
return result;
}
static bool
wfd_config_read_server(
config_t * config,
struct wfd_config_builder builder)
{
char const * vhost_name;
int rc = config_lookup_string(config, "server.vhost_name", &vhost_name);
if (CONFIG_TRUE == rc)
{
wfd_config_builder_set_server_vhostname(builder, vhost_name);
}
int port;
rc = config_lookup_int(config, "server.port", &port);
if (CONFIG_TRUE == rc)
{
wfd_config_builder_set_server_port(builder, port);
}
char const * cert;
rc = config_lookup_string(config, "server.tls.certificate", &cert);
if (CONFIG_TRUE == rc)
{
wfd_config_builder_set_server_cert(builder, cert);
}
char const * key;
rc = config_lookup_string(config, "server.tls.key", &key);
if (CONFIG_TRUE == rc)
{
wfd_config_builder_set_server_key(builder, key);
}
char const * doc_root;
rc = config_lookup_string(config, "server.document_root", &doc_root);
if (CONFIG_TRUE == rc)
{
wfd_config_builder_set_server_document_root(builder, doc_root);
}
return true;
}
static bool
wfd_config_read_authenticator(
config_setting_t * authenticator,
struct wfd_config_builder builder)
{
bool result = (NULL != authenticator);
char const * provider_name = NULL;
if (result)
{
int rc = config_setting_lookup_string(authenticator, "provider", &provider_name);
if (CONFIG_TRUE != rc)
{
WFD_ERROR("missing authentication provider");
result = false;
}
}
struct config_setting_t * settings = NULL;
if (result)
{
settings = config_setting_lookup(authenticator, "settings");
if (NULL == settings)
{
WFD_ERROR("missing authentication settings");
result = false;
}
}
if (result)
{
struct wfd_settings auth_settings;
wfd_settings_init(&auth_settings, settings);
result = wfd_config_builder_add_auth_provider(builder, provider_name, &auth_settings);
wfd_settings_cleanup(&auth_settings);
}
return result;
}
static bool
wfd_config_read_authentication(
config_t * config,
struct wfd_config_builder builder)
{
bool result = true;
config_setting_t * authentication = config_lookup(config, "authentication");
if (NULL != authentication)
{
int length = config_setting_length(authentication);
for (int i = 0; (result) && (i < length); i++)
{
config_setting_t * authenticator = config_setting_get_elem(authentication, i);
result = wfd_config_read_authenticator(authenticator, builder);
}
}
return result;
}
static bool
wfd_config_read_filesystems(
config_t * config,
struct wfd_config_builder builder)
{
bool result = true;
config_setting_t * filesystems = config_lookup(config, "filesystems");
if (NULL != filesystems)
{
int length = config_setting_length(filesystems);
for (int i = 0; i < length; i++)
{
config_setting_t * fs = config_setting_get_elem(filesystems, i);
if (NULL == fs)
{
WFD_ERROR("failed to load config: invalid filesystem section");
result = false;
break;
}
char const * name;
int rc = config_setting_lookup_string(fs, "name", &name);
if (rc != CONFIG_TRUE)
{
WFD_ERROR("failed to load config: missing required filesystem property \'name\'");
result = false;
break;
}
char const * mount_point;
rc = config_setting_lookup_string(fs, "mount_point", &mount_point);
if (rc != CONFIG_TRUE)
{
WFD_ERROR("failed to load config: missing required filesystem property \'mount_point\'");
result = false;
break;
}
result = wfd_config_builder_add_filesystem(builder, name, mount_point);
if (!result)
{
break;
}
}
}
return result;
}
static bool
wfd_config_load(
struct wfd_config_builder builder,
config_t * config)
{
bool result = wfd_config_check_version(config)
&& wfd_config_read_logger(config, builder)
&& wfd_config_read_server(config, builder)
&& wfd_config_read_authentication(config, builder)
&& wfd_config_read_filesystems(config, builder)
;
return result;
}
bool
wfd_config_load_file(
struct wfd_config_builder builder,
char const * filename)
{
bool result = false;
config_t config;
config_init(&config);
int rc = config_read_file(&config, filename);
if (CONFIG_TRUE == rc)
{
result = wfd_config_load(builder, &config);
}
else
{
WFD_ERROR("failed to load config: %s: %d: %s",
config_error_file(&config),
config_error_line(&config),
config_error_text(&config));
}
config_destroy(&config);
return result;
}
bool
wfd_config_load_string(
struct wfd_config_builder builder,
char const * contents)
{
bool result = false;
config_t config;
config_init(&config);
int rc = config_read_string(&config, contents);
if (CONFIG_TRUE == rc)
{
result = wfd_config_load(builder, &config);
}
else
{
WFD_ERROR("failed to load config: %d: %s",
config_error_line(&config),
config_error_text(&config));
}
config_destroy(&config);
return result;
}

View File

@ -0,0 +1,29 @@
#ifndef WFD_CONFIG_FACTORY_H
#define WFD_CONFIG_FACTORY_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#include "webfused/config/builder.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern bool
wfd_config_load_file(
struct wfd_config_builder builder,
char const * filename);
extern bool
wfd_config_load_string(
struct wfd_config_builder builder,
char const * contents);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,60 @@
#include "webfused/config/settings.h"
#include "webfused/config/settings_intern.h"
#include <libconfig.h>
#include <stddef.h>
void
wfd_settings_init(
struct wfd_settings * settings,
struct config_setting_t * setting)
{
settings->setting = setting;
}
void
wfd_settings_cleanup(
struct wfd_settings * settings)
{
settings->setting = NULL;
}
char const *
wfd_settings_get_string(
struct wfd_settings * settings,
char const * key)
{
if (NULL == settings) {return NULL; }
char const * result;
int rc = config_setting_lookup_string(settings->setting, key, &result);
return (CONFIG_TRUE == rc) ? result : NULL;
}
char const *
wfd_settings_get_string_or_default(
struct wfd_settings * settings,
char const * key,
char const * default_value)
{
if (NULL == settings) {return default_value; }
char const * result;
int rc = config_setting_lookup_string(settings->setting, key, &result);
return (CONFIG_TRUE == rc) ? result : default_value;
}
bool
wfd_settings_get_bool(
struct wfd_settings * settings,
char const * key)
{
if (NULL == settings) {return false; }
int result;
int rc = config_setting_lookup_bool(settings->setting, key, &result);
return ((CONFIG_TRUE == rc) && (CONFIG_TRUE == result));
}

View File

@ -0,0 +1,37 @@
#ifndef WFD_CONFIG_SETTINGS_H
#define WFD_CONFIG_SETTINGS_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern char const *
wfd_settings_get_string(
struct wfd_settings * settings,
char const * key);
extern char const *
wfd_settings_get_string_or_default(
struct wfd_settings * settings,
char const * key,
char const * default_value);
extern bool
wfd_settings_get_bool(
struct wfd_settings * settings,
char const * key);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
#ifndef WFD_CONFIG_SETTINGS_INTERN_H
#define WFD_CONFIG_SETTINGS_INTERN_H
#ifdef __cplusplus
extern "C"
{
#endif
struct config_setting_t;
struct wfd_settings
{
struct config_setting_t * setting;
};
extern void
wfd_settings_init(
struct wfd_settings * settings,
struct config_setting_t * setting);
extern void
wfd_settings_cleanup(
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

151
src/webfused/daemon.c Normal file
View File

@ -0,0 +1,151 @@
#include "webfused/daemon.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <webfuse_adapter.h>
#include "webfused/config/config.h"
#include "webfused/config/factory.h"
#include "webfused/log/log.h"
#include "webfused/log/logger.h"
#include "webfused/log/stderr_logger.h"
#define WFD_SERVICE_TIMEOUT (1 * 1000)
#define WFD_DEFAULT_CONFIG_FILE ("/etc/webfuse.conf")
struct args
{
char * config_file;
bool show_help;
};
static bool shutdown_requested = false;
static void show_help(void)
{
printf(
"webfused, Copyright (c) 2019-2020, webfused authors <https://github.com/falk-werner/webfused>\n"
"Websocket file system daemon\n"
"\n"
"Usage: webfused [-f <config file>] | -h\n"
"\n"
"Options:\n"
"\t-f, --config-file Path to config file (default: /etc/webfuse.conf)\n"
"\t-h, --help Print this message and terminate\n"
"\n");
}
static int parse_arguments(int argc, char * argv[], struct args * args)
{
static struct option const options[] =
{
{"config-file", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
args->config_file = strdup(WFD_DEFAULT_CONFIG_FILE);
args->show_help = false;
bool result = EXIT_SUCCESS;
bool finished = false;
optind = 0;
while ((!finished) && (EXIT_SUCCESS == result))
{
int option_index = 0;
int const c = getopt_long(argc, argv, "f:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
args->show_help = true;
finished = true;
break;
case 'f':
free(args->config_file);
args->config_file = strdup(optarg);
break;
default:
fprintf(stderr, "error: unknown argument\n");
result = EXIT_FAILURE;
break;
}
}
if (EXIT_SUCCESS != result)
{
args->show_help = true;
}
return result;
}
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
int wfd_daemon_run(int argc, char * argv[])
{
wfd_stderr_logger_init(WFD_LOGLEVEL_ALL, NULL);
struct args args;
int result = parse_arguments(argc, argv, &args);
if (!args.show_help)
{
signal(SIGINT, on_interrupt);
struct wfd_config * config = wfd_config_create();
struct wfd_config_builder builder = wfd_config_get_builder(config);
bool success = wfd_config_load_file(builder, args.config_file);
if (success)
{
struct wf_server_config * server_config = wfd_config_get_server_config(config);
struct wf_server * server = wf_server_create(server_config);
if (NULL != server)
{
while (!shutdown_requested)
{
wf_server_service(server, WFD_SERVICE_TIMEOUT);
}
wf_server_dispose(server);
}
else
{
fprintf(stderr, "fatal: unable start server\n");
result = EXIT_FAILURE;
}
}
else
{
fprintf(stderr, "fatal: failed to load server config\n");
result = EXIT_FAILURE;
}
wfd_config_dispose(config);
}
else
{
show_help();
}
wfd_logger_close();
free(args.config_file);
shutdown_requested = false;
return result;
}

15
src/webfused/daemon.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef WFD_DAEMON_H
#define WFD_DAEMON_H
#ifdef __cplusplus
extern "C"
{
#endif
extern int wfd_daemon_run(int argc, char * argv[]);
#ifdef __cplusplus
}
#endif
#endif

62
src/webfused/log/log.c Normal file
View File

@ -0,0 +1,62 @@
#include "webfused/log/log.h"
#include <strings.h>
char const *
wfd_log_level_tostring(int level)
{
switch (level)
{
case WFD_LOGLEVEL_NONE: return "none";
case WFD_LOGLEVEL_FATAL: return "fatal";
case WFD_LOGLEVEL_ERROR: return "error";
case WFD_LOGLEVEL_WARN: return "warn";
case WFD_LOGLEVEL_INFO: return "info";
case WFD_LOGLEVEL_DEBUG: return "debug";
case WFD_LOGLEVEL_ALL: return "all";
default: return "<unknown>";
}
}
bool
wfd_log_level_parse(
char const * level,
int * result)
{
bool success = true;
if (0 == strcasecmp("all", level))
{
*result = WFD_LOGLEVEL_ALL;
}
else if (0 == strcasecmp("none", level))
{
*result = WFD_LOGLEVEL_NONE;
}
else if (0 == strcasecmp("fatal", level))
{
*result = WFD_LOGLEVEL_FATAL;
}
else if (0 == strcasecmp("error", level))
{
*result = WFD_LOGLEVEL_ERROR;
}
else if ((0 == strcasecmp("warn", level)) ||
(0 == strcasecmp("warning", level)))
{
*result = WFD_LOGLEVEL_WARN;
}
else if (0 == strcasecmp("info", level))
{
*result = WFD_LOGLEVEL_INFO;
}
else if (0 == strcasecmp("debug", level))
{
*result = WFD_LOGLEVEL_DEBUG;
}
else
{
return false;
}
return success;
}

68
src/webfused/log/log.h Normal file
View File

@ -0,0 +1,68 @@
#ifndef WFD_LOG_H
#define WFD_LOG_H
#ifndef __cplusplus
#include <stdbool.h>
#include <stdarg.h>
#else
#include <cstdarg>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef WFD_LOGLEVEL
#define WFD_LOGLEVEL WFD_LOGLEVEL_ALL
#endif
#define WFD_LOGLEVEL_NONE -1
#define WFD_LOGLEVEL_FATAL 1
#define WFD_LOGLEVEL_ERROR 3
#define WFD_LOGLEVEL_WARN 4
#define WFD_LOGLEVEL_INFO 5
#define WFD_LOGLEVEL_DEBUG 7
#define WFD_LOGLEVEL_ALL 8
#define WFD_FATAL(...) \
WFD_LOG(WFD_LOGLEVEL_FATAL, __VA_ARGS__)
#define WFD_ERROR(...) \
WFD_LOG(WFD_LOGLEVEL_ERROR, __VA_ARGS__)
#define WFD_WARN(...) \
WFD_LOG(WFD_LOGLEVEL_WARN, __VA_ARGS__)
#define WFD_INFO(...) \
WFD_LOG(WFD_LOGLEVEL_INFO, __VA_ARGS__)
#define WFD_DEBUG(...) \
WFD_LOG(WFD_LOGLEVEL_DEBUG, __VA_ARGS__)
#define WFD_LOG(level, ...) \
do { \
if (WFD_LOGLEVEL >= (level)) { \
wfd_log((level), __VA_ARGS__); \
} \
} while (0)
extern void
wfd_log(
int level,
char const * format,
...);
extern char const *
wfd_log_level_tostring(int level);
extern bool
wfd_log_level_parse(
char const * level,
int * result);
#ifdef __cplusplus
}
#endif
#endif

86
src/webfused/log/logger.c Normal file
View File

@ -0,0 +1,86 @@
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include <stddef.h>
struct wfd_logger
{
int level;
wfd_logger_log_fn * log;
wfd_logger_onclose_fn * onclose;
void * user_data;
};
static void wfd_logger_default_log(
void * user_data,
int level,
char const * format,
va_list args);
static struct wfd_logger g_wfd_logger =
{
.level = WFD_LOGLEVEL_ALL,
.log = &wfd_logger_default_log,
.onclose = NULL,
.user_data = NULL
};
void
wfd_logger_init(
int level,
wfd_logger_log_fn * log,
wfd_logger_onclose_fn * onclose,
void * user_data)
{
wfd_logger_close();
g_wfd_logger.level = level;
g_wfd_logger.log = log;
g_wfd_logger.onclose = onclose;
g_wfd_logger.user_data = user_data;
}
void
wfd_logger_close(void)
{
if (NULL != g_wfd_logger.onclose)
{
g_wfd_logger.onclose(g_wfd_logger.user_data);
}
g_wfd_logger.level = WFD_LOGLEVEL_ALL;
g_wfd_logger.log = &wfd_logger_default_log;
g_wfd_logger.onclose = NULL;
g_wfd_logger.user_data = NULL;
}
void
wfd_log(
int level,
char const * format,
...)
{
if (g_wfd_logger.level >= level)
{
va_list args;
va_start(args, format);
g_wfd_logger.log(
g_wfd_logger.user_data,
level,
format,
args);
va_end(args);
}
}
static void wfd_logger_default_log(
void * user_data,
int level,
char const * format,
va_list args)
{
(void) user_data;
(void) level;
(void) format;
(void) args;
}

40
src/webfused/log/logger.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef WFD_LOGGER_H
#define WFD_LOGGER_H
#ifndef __cplusplus
#include <stdarg.h>
#else
#include <cstdarg>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
typedef void
wfd_logger_log_fn(
void * user_data,
int level,
char const * format,
va_list args);
typedef void
wfd_logger_onclose_fn(
void * user_data);
extern void
wfd_logger_init(
int level,
wfd_logger_log_fn * log,
wfd_logger_onclose_fn * onclose,
void * user_data);
extern void
wfd_logger_close(void);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,30 @@
#include "webfused/log/manager.h"
#include "webfused/log/log.h"
#include "webfused/log/stderr_logger.h"
#include "webfused/log/syslog_logger.h"
#include <string.h>
bool
wfd_log_manager_set_logger(
char const * provider,
int level,
struct wfd_settings * settings)
{
bool result = false;
if (0 == strcmp("syslog", provider))
{
result = wfd_syslog_logger_init(level, settings);
}
else if (0 == strcmp("stderr", provider))
{
result = wfd_stderr_logger_init(level, settings);
}
else
{
WFD_ERROR("failed to init log: unknown provider \'%s\'", provider);
}
return result;
}

View File

@ -0,0 +1,25 @@
#ifndef WFD_LOG_MANAGER_H
#define WFD_LOG_MANAGER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern bool
wfd_log_manager_set_logger(
char const * provider,
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,29 @@
#include "webfused/log/stderr_logger.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include <stdio.h>
#include <stdlib.h>
static void
wfd_stderr_logger_log(
void * user_data,
int level,
char const * format,
va_list args)
{
fprintf(stderr, "%s: ", wfd_log_level_tostring(level));
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
}
bool
wfd_stderr_logger_init(
int level,
struct wfd_settings * settings)
{
(void) settings;
wfd_logger_init(level, &wfd_stderr_logger_log, NULL, NULL);
return true;
}

View File

@ -0,0 +1,24 @@
#ifndef WFD_LOG_STDERR_LOGGER_H
#define WFD_LOG_STDERR_LOGGER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern bool
wfd_stderr_logger_init(
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,122 @@
#include "webfused/log/syslog_logger.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "webfused/config/settings.h"
#include <syslog.h>
#include <strings.h>
#include <stddef.h>
static int
wfd_syslog_logger_to_priority(
int level)
{
switch (level)
{
case WFD_LOGLEVEL_FATAL: return LOG_CRIT;
case WFD_LOGLEVEL_ERROR: return LOG_ERR;
case WFD_LOGLEVEL_WARN: return LOG_WARNING;
case WFD_LOGLEVEL_INFO: return LOG_INFO;
case WFD_LOGLEVEL_DEBUG: return LOG_DEBUG;
default: return LOG_NOTICE;
}
}
static void
wfd_syslog_logger_log(
void * user_data,
int level,
char const * format,
va_list args)
{
(void) user_data;
int prio = wfd_syslog_logger_to_priority(level);
vsyslog(prio, format, args);
}
static void
wfd_syslog_logger_close(
void * user_data)
{
closelog();
}
struct wfd_syslog_facility
{
char const * name;
int value;
};
static bool
wfd_syslog_logger_parse_facility(
char const * facility,
int * result)
{
static struct wfd_syslog_facility const facilities[] =
{
{"auth", LOG_AUTH},
{"authpriv", LOG_AUTHPRIV},
{"cron", LOG_CRON},
{"daemon", LOG_DAEMON},
{"fpt", LOG_FTP},
{"kern", LOG_KERN},
{"local0", LOG_LOCAL0},
{"local1", LOG_LOCAL1},
{"local2", LOG_LOCAL2},
{"local3", LOG_LOCAL3},
{"local4", LOG_LOCAL4},
{"local5", LOG_LOCAL5},
{"local6", LOG_LOCAL6},
{"local7", LOG_LOCAL7},
{"lpr", LOG_LPR},
{"mail", LOG_MAIL},
{"news", LOG_NEWS},
{"syslog", LOG_SYSLOG},
{"user", LOG_USER},
{"uucp", LOG_UUCP}
};
static size_t const facilites_count = sizeof(facilities) / sizeof(facilities[0]);
for (size_t i = 0; i < facilites_count; i++)
{
if (0 == strcasecmp(facility, facilities[i].name))
{
*result = facilities[i].value;
return true;
}
}
return false;
}
bool
wfd_syslog_logger_init(
int level,
struct wfd_settings * settings)
{
char const * ident = wfd_settings_get_string_or_default(settings, "ident", "webfused");
char const * facility_str = wfd_settings_get_string_or_default(settings, "facility", "daemon");
bool log_pid = wfd_settings_get_bool(settings, "log_pid");
int facility;
bool result = wfd_syslog_logger_parse_facility(facility_str, &facility);
if (result)
{
int options = (log_pid) ? LOG_PID : 0;
wfd_logger_init(level,
&wfd_syslog_logger_log,
&wfd_syslog_logger_close,
NULL);
openlog(ident, options, facility);
}
else
{
WFD_ERROR("failed to init syslog logger: invalid log facility: \'%s\'", facility_str);
}
return result;
}

View File

@ -0,0 +1,24 @@
#ifndef WFD_LOG_SYSLOG_LOGGER_H
#define WFD_LOG_SYSLOG_LOGGER_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_settings;
extern bool
wfd_syslog_logger_init(
int level,
struct wfd_settings * settings);
#ifdef __cplusplus
}
#endif
#endif

6
src/webfused/main.c Normal file
View File

@ -0,0 +1,6 @@
#include "webfused/daemon.h"
int main(int argc, char * argv[])
{
return wfd_daemon_run(argc, argv);
}

View File

@ -0,0 +1,150 @@
#include "webfused/mountpoint_factory.h"
#include "webfused/log/log.h"
#include <webfuse/adapter/mountpoint.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#define WFD_FILESYSTEM_DEFAULT_CAPACITY 16
struct wfd_filesystem
{
char * name;
char * mount_point;
bool in_use;
};
struct wfd_mountpoint_factory
{
struct wfd_filesystem * filesystems;
size_t capacity;
size_t count;
};
static struct wfd_filesystem *
wfd_mountpoint_factory_find(
struct wfd_mountpoint_factory * factory,
char const * name)
{
for (size_t i = 0; i < factory->count; i++)
{
struct wfd_filesystem * filesystem = &(factory->filesystems[i]);
if (0 == strcmp(name, filesystem->name))
{
return filesystem;
}
}
return NULL;
}
static void
wfd_mountpoint_factory_release_mountpoint(
void * user_data)
{
bool * in_use = user_data;
*in_use = false;
}
struct wfd_mountpoint_factory *
wfd_mountpoint_factory_create(void)
{
struct wfd_mountpoint_factory * factory = malloc(sizeof(struct wfd_mountpoint_factory));
factory->filesystems = malloc(sizeof(struct wfd_filesystem) * WFD_FILESYSTEM_DEFAULT_CAPACITY);
factory->count = 0;
factory->capacity = WFD_FILESYSTEM_DEFAULT_CAPACITY;
return factory;
}
void
wfd_mountpoint_factory_dispose(
struct wfd_mountpoint_factory * factory)
{
for(size_t i = 0; i < factory->count; i++)
{
struct wfd_filesystem * filesystem = &(factory->filesystems[i]);
free(filesystem->name);
free(filesystem->mount_point);
}
free(factory->filesystems);
free(factory);
}
bool
wfd_mountpoint_factory_add_filesystem(
struct wfd_mountpoint_factory * factory,
char const * name,
char const * mount_point)
{
bool result = (NULL == wfd_mountpoint_factory_find(factory, name));
if (!result)
{
WFD_ERROR("mount_point already defined: \'%s\'", mount_point);
}
char * path = NULL;
if (result)
{
mkdir(mount_point, 0755);
path = realpath(mount_point, NULL);
if (NULL == path)
{
WFD_ERROR("invalid mount_point: \'%s\'", mount_point);
result = false;
}
}
if (result)
{
if (factory->count >= factory->capacity)
{
factory->capacity *= 2;
factory->filesystems = realloc(factory->filesystems,
sizeof(struct wfd_filesystem) * factory->capacity);
}
struct wfd_filesystem * actual = &(factory->filesystems[factory->count]);
actual->name = strdup(name);
actual->mount_point = path;
actual->in_use = false;
factory->count++;
}
return result;
}
extern struct wf_mountpoint *
wfd_mountpoint_factory_create_mountpoint(
char const * filesystem,
void * user_data)
{
struct wfd_mountpoint_factory * factory = user_data;
struct wfd_filesystem * fs = wfd_mountpoint_factory_find(factory, filesystem);
if (NULL == fs)
{
WFD_INFO("failed to create mountpoint: filesystem \'%s\' not found", filesystem);
return NULL;
}
if (fs->in_use)
{
WFD_INFO("failed to create mountpoint: filesystem \'%s\' already in use", filesystem);
return NULL;
}
fs->in_use = true;
struct wf_mountpoint * result = wf_mountpoint_create(fs->mount_point);
wf_mountpoint_set_userdata(result,
&fs->in_use, &wfd_mountpoint_factory_release_mountpoint);
WFD_INFO("create mountpoint \'%s\' at path \'%s\': %s",
filesystem,
fs->mount_point,
result ? "success" : "failure");
return result;
}

View File

@ -0,0 +1,39 @@
#ifndef WFD_MOUNTPOINT_FACTORY_H
#define WFD_MOUNTPOINT_FACTORY_H
#include "webfuse/adapter/mountpoint_factory.h"
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wfd_mountpoint_factory;
extern struct wfd_mountpoint_factory *
wfd_mountpoint_factory_create(void);
extern void
wfd_mountpoint_factory_dispose(
struct wfd_mountpoint_factory * factory);
extern bool
wfd_mountpoint_factory_add_filesystem(
struct wfd_mountpoint_factory * factory,
char const * name,
char const * mount_point);
extern struct wf_mountpoint *
wfd_mountpoint_factory_create_mountpoint(
char const * filesystem,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

4
test/invalid.conf Normal file
View File

@ -0,0 +1,4 @@
# This config file is invalid,
# since "." is not allowed as separator
version.major = 1

111
test/mock_config_builder.cc Normal file
View File

@ -0,0 +1,111 @@
#include "mock_config_builder.hpp"
extern "C"
{
using webfused_test::IConfigBuilder;
static void
wfd_MockConfigBuilder_set_server_vhostname(
void * data,
char const * vhost_name)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
builder->setServerVhostname(vhost_name);
}
static void
wfd_MockConfigBuilder_set_server_port(
void * data,
int port)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
builder->setServerPort(port);
}
static void
wfd_MockConfigBuilder_set_server_key(
void * data,
char const * key_path)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
builder->setServerKey(key_path);
}
static void
wfd_MockConfigBuilder_set_server_cert(
void * data,
char const * cert_path)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
builder->setServerCert(cert_path);
}
static void
wfd_MockConfigBuilder_set_server_document_root(
void * data,
char const * document_root)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
builder->setServerDocumentRoot(document_root);
}
static bool
wfd_MockConfigBuilder_add_auth_provider(
void * data,
char const * provider,
struct wfd_settings * settings)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
return builder->addAuthProvider(provider, settings);
}
static bool
wfd_MockConfigBuilder_add_filesystem(
void * data,
char const * name,
char const * mountpoint)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
return builder->addFilesystem(name, mountpoint);
}
static bool
wfd_MockConfigBuilder_set_logger(
void * data,
char const * provider,
int level,
struct wfd_settings * settings)
{
auto * builder = reinterpret_cast<IConfigBuilder*>(data);
return builder->setLogger(provider, level, settings);
}
static const wfd_config_builder_vtable wfd_MockConfigBuilder_vtable =
{
&wfd_MockConfigBuilder_set_server_vhostname,
&wfd_MockConfigBuilder_set_server_port,
&wfd_MockConfigBuilder_set_server_key,
&wfd_MockConfigBuilder_set_server_cert,
&wfd_MockConfigBuilder_set_server_document_root,
&wfd_MockConfigBuilder_add_auth_provider,
&wfd_MockConfigBuilder_add_filesystem,
&wfd_MockConfigBuilder_set_logger
};
}
namespace webfused_test
{
struct wfd_config_builder MockConfigBuilder::getBuilder()
{
IConfigBuilder * config_builder = this;
wfd_config_builder builder = {
&wfd_MockConfigBuilder_vtable,
reinterpret_cast<void*>(config_builder)
};
return builder;
}
}

View File

@ -0,0 +1,42 @@
#ifndef WFD_MOCK_CONFIG_BUILDER_HPP
#define WFD_MOCK_CONFIG_BUILDER_HPP
#include <gmock/gmock.h>
#include "webfused/config/builder.h"
namespace webfused_test
{
class IConfigBuilder
{
public:
virtual ~IConfigBuilder() = default;
virtual void setServerVhostname(char const * vhostname) = 0;
virtual void setServerPort(int port) = 0;
virtual void setServerKey(char const * key_path) = 0;
virtual void setServerCert(char const * cert_path) = 0;
virtual void setServerDocumentRoot(char const * document_root) = 0;
virtual bool addAuthProvider(char const * provider, wfd_settings * settings) = 0;
virtual bool addFilesystem(char const * name, char const * mountpoint) = 0;
virtual bool setLogger(char const * provider, int level, wfd_settings * settings) = 0;
};
class MockConfigBuilder: public IConfigBuilder
{
public:
~MockConfigBuilder() override = default;
MOCK_METHOD1(setServerVhostname, void (char const * vhostname));
MOCK_METHOD1(setServerPort, void (int port));
MOCK_METHOD1(setServerKey, void (char const * key_path));
MOCK_METHOD1(setServerCert, void (char const * cert_path));
MOCK_METHOD1(setServerDocumentRoot, void (char const * document_root));
MOCK_METHOD2(addAuthProvider, bool (char const * provider, wfd_settings * settings));
MOCK_METHOD2(addFilesystem, bool (char const * name, char const * mountpoint));
MOCK_METHOD3(setLogger, bool (char const * provider, int level, wfd_settings * settings));
struct wfd_config_builder getBuilder();
};
}
#endif

64
test/mock_credentials.cc Normal file
View File

@ -0,0 +1,64 @@
#include "mock_credentials.hpp"
extern "C"
{
using webfused_test::ICredentials;
static ICredentials * wfd_mock_credentials = nullptr;
extern char const *
__real_wf_credentials_type(
struct wf_credentials const * credentials);
char const *
__wrap_wf_credentials_type(
struct wf_credentials const * credentials)
{
if (nullptr == wfd_mock_credentials)
{
return __real_wf_credentials_type(credentials);
}
else
{
return wfd_mock_credentials->type();
}
}
extern char const * __real_wf_credentials_get(
struct wf_credentials const * credentials,
char const * key);
char const * __wrap_wf_credentials_get(
struct wf_credentials const * credentials,
char const * key)
{
if (nullptr == wfd_mock_credentials)
{
return __real_wf_credentials_get(credentials, key);
}
else
{
return wfd_mock_credentials->get(key);
}
}
}
namespace webfused_test
{
MockCredentials::MockCredentials()
{
wfd_mock_credentials = this;
}
MockCredentials::~MockCredentials()
{
wfd_mock_credentials = nullptr;
}
}

29
test/mock_credentials.hpp Normal file
View File

@ -0,0 +1,29 @@
#ifndef WFD_MOCK_CREDENTIALS_HPP
#define WFD_MOCK_CREDENTIALS_HPP
#include <gmock/gmock.h>
#include "webfuse/adapter/credentials.h"
namespace webfused_test
{
class ICredentials
{
public:
virtual ~ICredentials() = default;
virtual char const * type() = 0;
virtual char const * get(char const * key) = 0;
};
class MockCredentials: public ICredentials
{
public:
MockCredentials();
virtual ~MockCredentials();
MOCK_METHOD0(type, char const*());
MOCK_METHOD1(get, char const *(char const * key));
};
}
#endif

58
test/mock_logger.cc Normal file
View File

@ -0,0 +1,58 @@
#include "mock_logger.hpp"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
namespace webfused_test
{
MockLogger::MockLogger(bool omit_init)
: close_on_destruct(!omit_init)
{
if (!omit_init)
{
wfd_logger_init(
WFD_LOGLEVEL_ALL,
&wfd_MockLogger_log,
&wfd_MockLogger_onclose,
getUserData());
}
}
MockLogger::~MockLogger()
{
if (close_on_destruct)
{
wfd_logger_close();
}
}
void * MockLogger::getUserData()
{
ILogger * logger = this;
return reinterpret_cast<void*>(logger);
}
}
extern "C"
{
using webfused_test::ILogger;
void wfd_MockLogger_log(
void * user_data,
int level,
char const * format,
va_list args)
{
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
logger->log(level, format, args);
}
void wfd_MockLogger_onclose(
void * user_data)
{
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
logger->onclose();
}
}

47
test/mock_logger.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef WFD_MOCK_LOGGER_HPP
#define WFD_MOCK_LOGGER_HPP
#include <gmock/gmock.h>
#include <cstdarg>
namespace webfused_test
{
class ILogger
{
public:
virtual ~ILogger() = default;
virtual void log(int level, char const * format, va_list args) = 0;
virtual void onclose() = 0;
};
class MockLogger: public ILogger
{
public:
explicit MockLogger(bool omit_init = false);
~MockLogger() override;
MOCK_METHOD3(log, void(int level, char const * format, va_list args));
MOCK_METHOD0(onclose, void(void));
void * getUserData();
private:
bool close_on_destruct;
};
}
extern "C"
{
extern void wfd_MockLogger_log(
void * user_data,
int level,
char const * format,
va_list args);
extern void wfd_MockLogger_onclose(
void * user_data);
}
#endif

87
test/mock_settings.cc Normal file
View File

@ -0,0 +1,87 @@
#include "mock_settings.hpp"
extern "C"
{
using webfused_test::ISettings;
static ISettings * wfd_mock_settings = nullptr;
extern char const *
__real_wfd_settings_get_string(
struct wfd_settings * settings,
char const * key);
extern char const *
__real_wfd_settings_get_string_or_default(
struct wfd_settings * settings,
char const * key,
char const * default_value);
extern bool
__real_wfd_settings_get_bool(
struct wfd_settings * settings,
char const * key);
char const *
__wrap_wfd_settings_get_string(
struct wfd_settings * settings,
char const * key)
{
if (nullptr == wfd_mock_settings)
{
return __real_wfd_settings_get_string(settings, key);
}
else
{
return wfd_mock_settings->getString(key);
}
}
char const *
__wrap_wfd_settings_get_string_or_default(
struct wfd_settings * settings,
char const * key,
char const * default_value)
{
if (nullptr == wfd_mock_settings)
{
return __real_wfd_settings_get_string_or_default(
settings, key, default_value);
}
else
{
return wfd_mock_settings->getStringOrDefault(key, default_value);
}
}
bool
__wrap_wfd_settings_get_bool(
struct wfd_settings * settings,
char const * key)
{
if (nullptr == wfd_mock_settings)
{
return __real_wfd_settings_get_bool(settings, key);
}
else
{
return wfd_mock_settings->getBool(key);
}
}
}
namespace webfused_test
{
MockSettings::MockSettings()
{
wfd_mock_settings = this;
}
MockSettings::~MockSettings()
{
wfd_mock_settings = nullptr;
}
}

33
test/mock_settings.hpp Normal file
View File

@ -0,0 +1,33 @@
#ifndef WFD_MOCK_AUTH_SETTINGS_HPP
#define WFD_MOCK_AUTH_SETTINGS_HPP
#include <gmock/gmock.h>
#include "webfused/config/settings.h"
namespace webfused_test
{
class ISettings
{
public:
virtual ~ISettings() = default;
virtual char const * getString(char const * key) = 0;
virtual char const * getStringOrDefault(char const * key, char const * default_value) = 0;
virtual bool getBool(char const * key) = 0;
};
class MockSettings: public ISettings
{
public:
MockSettings();
~MockSettings() override;
MOCK_METHOD1(getString, char const * (char const * key));
MOCK_METHOD2(getStringOrDefault, char const * (char const * key, char const * default_value));
MOCK_METHOD1(getBool, bool (char const * key));
};
}
#endif

20
test/test_auth_factory.cc Normal file
View File

@ -0,0 +1,20 @@
#include <gtest/gtest.h>
#include "webfused/auth/factory.h"
#include "webfused/auth/authenticator.h"
#include "webfused/log/log.h"
#include "mock_logger.hpp"
using ::testing::_;
using ::webfused_test::MockLogger;
TEST(auth_factory, fail_unknown_provider)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_authenticator authenticator;
bool result = wfd_authenticator_create("unknown", NULL, &authenticator);
ASSERT_FALSE(result);
}

105
test/test_config.cc Normal file
View File

@ -0,0 +1,105 @@
#include <gtest/gtest.h>
#include "webfused/config/config.h"
#include "mock_settings.hpp"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock_logger.hpp"
using ::webfused_test::MockLogger;
using ::testing::_;
using ::webfused_test::MockSettings;
using ::testing::Return;
using ::testing::StrEq;
TEST(config, server_config)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_builder builder = wfd_config_get_builder(config);
wfd_config_builder_set_server_vhostname(builder, "localhost");
wfd_config_builder_set_server_port(builder, 8443);
wfd_config_builder_set_server_key(builder, "/path/to/key.pem");
wfd_config_builder_set_server_cert(builder, "/path/to/cert.pem");
wfd_config_builder_set_server_document_root(builder, "/var/www");
wf_server_config * server_config = wfd_config_get_server_config(config);
ASSERT_NE(nullptr, server_config);
wfd_config_dispose(config);
}
TEST(config, auth_config)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_builder builder = wfd_config_get_builder(config);
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("/any/path"));
bool success = wfd_config_builder_add_auth_provider(builder, "file", nullptr);
ASSERT_TRUE(success);
wfd_config_dispose(config);
}
TEST(config, auth_config_failed_to_add_second_provider)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_builder builder = wfd_config_get_builder(config);
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("/any/path"));
bool success = wfd_config_builder_add_auth_provider(builder, "file", nullptr);
ASSERT_TRUE(success);
success = wfd_config_builder_add_auth_provider(builder, "file", nullptr);
ASSERT_FALSE(success);
wfd_config_dispose(config);
}
TEST(config, auth_config_failed_to_add_unknown_provider)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_builder builder = wfd_config_get_builder(config);
bool success = wfd_config_builder_add_auth_provider(builder, "unknown", nullptr);
ASSERT_FALSE(success);
wfd_config_dispose(config);
}
TEST(config, add_filesystem)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_builder builder = wfd_config_get_builder(config);
bool success = wfd_config_builder_add_filesystem(builder, "test", "/tmp/test");
ASSERT_TRUE(success);
wfd_config_dispose(config);
}
TEST(config, set_logger)
{
wfd_config * config = wfd_config_create();
ASSERT_NE(nullptr, config);
wfd_config_builder builder = wfd_config_get_builder(config);
bool success = wfd_config_builder_set_logger(builder, "stderr", WFD_LOGLEVEL_ALL, nullptr);
ASSERT_TRUE(success);
wfd_config_dispose(config);
}

548
test/test_config_factory.cc Normal file
View File

@ -0,0 +1,548 @@
#include <gtest/gtest.h>
#include "webfused/config/factory.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock_logger.hpp"
#include "mock_config_builder.hpp"
using ::testing::_;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
using ::webfused_test::MockConfigBuilder;
TEST(config, is_loadable)
{
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setLogger(_,_,_)).Times(1).WillOnce(Return(true));
EXPECT_CALL(builder, setServerVhostname(StrEq("localhost"))).Times(1);
EXPECT_CALL(builder, setServerPort(8080)).Times(1);
EXPECT_CALL(builder, addAuthProvider(_, _)).Times(1).WillOnce(Return(true));
EXPECT_CALL(builder, addFilesystem(_,_)).Times(1).WillOnce(Return(true));
bool result = wfd_config_load_file(builder.getBuilder(), "webfused.conf");
ASSERT_TRUE(result);
}
TEST(config, minimal_config)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const minimal[] = "version = { major = 1, minor = 0 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), minimal);
ASSERT_TRUE(result);
}
TEST(config, invalid_config)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const syntax_error[] = "version.major = 1\n";
bool result = wfd_config_load_string(builder.getBuilder(), syntax_error);
ASSERT_FALSE(result);
}
TEST(config, invalid_config_file)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
bool result = wfd_config_load_file(builder.getBuilder(), "invalid.conf");
ASSERT_FALSE(result);
}
TEST(config, invalid_major_version_too_low)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const too_low[] = "version = { major = 0, minor = 0 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), too_low);
ASSERT_FALSE(result);
}
TEST(config, invalid_major_version_too_high)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const too_high[] = "version = { major = 2, minor = 0 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), too_high);
ASSERT_FALSE(result);
}
TEST(config, invalid_missing_major_version)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const too_high[] = "version = { minor = 0 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), too_high);
ASSERT_FALSE(result);
}
TEST(config, invalid_missing_minor_version)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const too_high[] = "version = { major = 1 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), too_high);
ASSERT_FALSE(result);
}
TEST(config, valid_older_minor)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const valid[] = "version = { major = 1, minor = -1 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), valid);
ASSERT_TRUE(result);
}
TEST(config, valid_newer_minor)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const valid[] = "version = { major = 1, minor = 1 }\n";
bool result = wfd_config_load_string(builder.getBuilder(), valid);
ASSERT_TRUE(result);
}
TEST(config, vhost_name)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setServerVhostname(StrEq("some.host"))).Times(1);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"server:\n"
"{\n"
" vhost_name = \"some.host\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, port)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setServerPort(54321)).Times(1);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"server:\n"
"{\n"
" port = 54321\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, tls_certificate)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setServerCert(StrEq("/path/to/cert.pem"))).Times(1);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"server:\n"
"{\n"
" tls:\n"
" {\n"
" certificate = \"/path/to/cert.pem\"\n"
" }\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, tls_key)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setServerKey(StrEq("/path/to/key.pem"))).Times(1);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"server:\n"
"{\n"
" tls:\n"
" {\n"
" key = \"/path/to/key.pem\"\n"
" }\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, document_root)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setServerDocumentRoot(StrEq("/var/www"))).Times(1);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"server:\n"
"{\n"
" document_root = \"/var/www\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, authentication)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addAuthProvider(_, _)).Times(1).WillOnce(Return(true));
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" settings: { }\n"
" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, failed_create_authenticator)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addAuthProvider(_, _)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" settings: { }\n"
" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, failed_missing_auth_provider)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"authentication:\n"
"(\n"
" {\n"
" settings: { }\n"
" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, failed_missing_auth_settings)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"authentication:\n"
"(\n"
" {\n"
" provider = \"test\"\n"
" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, filesystems)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addFilesystem(_, _)).Times(1).WillOnce(Return(true));
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, filesystems_empty)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addFilesystem(_, _)).Times(0);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"filesystems:\n"
"(\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, filesystems_failed_add)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addFilesystem(_, _)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\", mount_point = \"/tmp/test\" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, filesystems_failed_missing_name)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addFilesystem(_, _)).Times(0);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"filesystems:\n"
"(\n"
" {mount_point = \"/tmp/test\" }\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, filesystems_failed_missing_mountpoint)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, addFilesystem(_, _)).Times(0);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"filesystems:\n"
"(\n"
" {name = \"foo\"}\n"
")\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, log)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setLogger(_, _, _)).Times(1).WillOnce(Return(true));
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
" level = \"all\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_TRUE(result);
}
TEST(config, log_fail_set_logger)
{
MockLogger logger;
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setLogger(_, _, _)).Times(1).WillOnce(Return(false));
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
" level = \"all\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, log_fail_missing_provider)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setLogger(_, _, _)).Times(0);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"log:\n"
"{\n"
" level = \"all\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, log_fail_missing_level)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setLogger(_, _, _)).Times(0);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
" level = \"fancy\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}
TEST(config, log_fail_invalid_level)
{
MockLogger logger;
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
StrictMock<MockConfigBuilder> builder;
EXPECT_CALL(builder, setLogger(_, _, _)).Times(0);
char const config_text[] =
"version = { major = 1, minor = 0 }\n"
"log:\n"
"{\n"
" provider = \"stderr\"\n"
"}\n"
;
bool result = wfd_config_load_string(builder.getBuilder(), config_text);
ASSERT_FALSE(result);
}

68
test/test_daemon.cc Normal file
View File

@ -0,0 +1,68 @@
#include "webfused/daemon.h"
#include <gtest/gtest.h>
#include <cstdlib>
#include <chrono>
#include <thread>
TEST(daemon, print_usage)
{
char argv0[] = "daemon";
char argv1[] = "--help";
char * argv[] = { argv0, argv1, NULL};
int exit_code = wfd_daemon_run(2, argv);
ASSERT_EQ(EXIT_SUCCESS, exit_code);
}
TEST(daemon, print_usage_short)
{
char argv0[] = "daemon";
char argv1[] = "-h";
char * argv[] = { argv0, argv1, NULL};
int exit_code = wfd_daemon_run(2, argv);
ASSERT_EQ(EXIT_SUCCESS, exit_code);
}
TEST(daemon, fail_invalid_argument)
{
char argv0[] = "daemon";
char argv1[] = "-x";
char * argv[] = { argv0, argv1, NULL};
int exit_code = wfd_daemon_run(2, argv);
ASSERT_EQ(EXIT_FAILURE, exit_code);
}
TEST(daemon, fail_invalid_config_file)
{
char argv0[] = "daemon";
char argv1[] = "-f";
char argv2[] = "invalid.conf";
char * argv[] = { argv0, argv1, argv2, NULL};
int exit_code = wfd_daemon_run(3, argv);
ASSERT_EQ(EXIT_FAILURE, exit_code);
}
void defered_raise()
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
raise(SIGINT);
}
TEST(daemon, run)
{
char argv0[] = "daemon";
char argv1[] = "-f";
char argv2[] = "webfused.conf";
char * argv[] = { argv0, argv1, argv2, NULL};
std::thread thread(defered_raise);
int exit_code = wfd_daemon_run(3, argv);
ASSERT_EQ(EXIT_SUCCESS, exit_code);
thread.join();
}

View File

@ -0,0 +1,158 @@
#include "webfused/auth/file_authenticator.h"
#include "webfused/auth/authenticator.h"
#include "webfused/config/settings.h"
#include "webfused/auth/factory.h"
#include "mock_credentials.hpp"
#include "mock_settings.hpp"
#include <gtest/gtest.h>
#include <libconfig.h>
using ::webfused_test::MockSettings;
using ::webfused_test::MockCredentials;
using ::testing::Return;
using ::testing::StrEq;
TEST(file_authenticator, create)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, create_fail_missing_file)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return(nullptr));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_FALSE(success);
}
TEST(file_authenticator, create_via_factory)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_authenticator_create("file", nullptr, &authenticator);
ASSERT_TRUE(success);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("secret"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_TRUE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_wrong_passwd)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("unkown"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_no_passwd_file)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("unknown_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("secred"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_missing_username)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return(nullptr));
EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return("unkown"));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, authenticate_fail_missing_password)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("test_passwd.json"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
MockCredentials creds;
EXPECT_CALL(creds, get(StrEq("username"))).Times(1).WillOnce(Return("bob"));
EXPECT_CALL(creds, get(StrEq("password"))).Times(1).WillOnce(Return(nullptr));
bool is_authenticated = wfd_authenticator_authenticate(authenticator, nullptr);
ASSERT_FALSE(is_authenticated);
wfd_authenticator_dispose(authenticator);
}
TEST(file_authenticator, get_type)
{
MockSettings settings;
EXPECT_CALL(settings, getString(StrEq("file"))).Times(1).WillOnce(Return("/any/path"));
wfd_authenticator authenticator;
bool success = wfd_file_authenticator_create(nullptr, &authenticator);
ASSERT_TRUE(success);
ASSERT_STREQ("username", wfd_authenticator_get_type(authenticator));
wfd_authenticator_dispose(authenticator);
}

170
test/test_log.cc Normal file
View File

@ -0,0 +1,170 @@
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock_logger.hpp"
using ::testing::_;
using ::testing::StrEq;
using ::webfused_test::MockLogger;
TEST(log, fatal)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_FATAL, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_FATAL("too bad");
wfd_logger_close();
}
TEST(log, error)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_ERROR("too bad");
wfd_logger_close();
}
TEST(log, warn)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_WARN("too bad");
wfd_logger_close();
}
TEST(log, info)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_INFO("too bad");
wfd_logger_close();
}
TEST(log, debug)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_DEBUG, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_DEBUG("too bad");
wfd_logger_close();
}
TEST(log, respect_loglevel)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(_, _, _)).Times(0);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_DEBUG("too bad");
wfd_logger_close();
}
TEST(log, log_same_loglevel)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(1);
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
WFD_WARN("too bad");
wfd_logger_close();
}
TEST(log, omit_onclose_if_nullptr)
{
MockLogger logger(true);
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
EXPECT_CALL(logger, onclose()).Times(0);
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, nullptr, logger.getUserData());
WFD_WARN("too bad");
wfd_logger_close();
}
TEST(log, default_log)
{
WFD_ERROR("trigger log");
}
TEST(log, loglevel_parse)
{
int level;
ASSERT_TRUE(wfd_log_level_parse("fatal", &level));
ASSERT_EQ(WFD_LOGLEVEL_FATAL, level);
ASSERT_TRUE(wfd_log_level_parse("FATAL", &level));
ASSERT_EQ(WFD_LOGLEVEL_FATAL, level);
ASSERT_TRUE(wfd_log_level_parse("error", &level));
ASSERT_EQ(WFD_LOGLEVEL_ERROR, level);
ASSERT_TRUE(wfd_log_level_parse("ERROR", &level));
ASSERT_EQ(WFD_LOGLEVEL_ERROR, level);
ASSERT_TRUE(wfd_log_level_parse("warn", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("WARN", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("warning", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("WARNING", &level));
ASSERT_EQ(WFD_LOGLEVEL_WARN, level);
ASSERT_TRUE(wfd_log_level_parse("info", &level));
ASSERT_EQ(WFD_LOGLEVEL_INFO, level);
ASSERT_TRUE(wfd_log_level_parse("INFO", &level));
ASSERT_EQ(WFD_LOGLEVEL_INFO, level);
ASSERT_TRUE(wfd_log_level_parse("debug", &level));
ASSERT_EQ(WFD_LOGLEVEL_DEBUG, level);
ASSERT_TRUE(wfd_log_level_parse("DEBUG", &level));
ASSERT_EQ(WFD_LOGLEVEL_DEBUG, level);
ASSERT_FALSE(wfd_log_level_parse("<invalid>", &level));
ASSERT_TRUE(wfd_log_level_parse("all", &level));
ASSERT_EQ(WFD_LOGLEVEL_ALL, level);
ASSERT_TRUE(wfd_log_level_parse("ALL", &level));
ASSERT_EQ(WFD_LOGLEVEL_ALL, level);
ASSERT_TRUE(wfd_log_level_parse("none", &level));
ASSERT_EQ(WFD_LOGLEVEL_NONE, level);
ASSERT_TRUE(wfd_log_level_parse("NONE", &level));
ASSERT_EQ(WFD_LOGLEVEL_NONE, level);
}
TEST(log, log_level_tostring)
{
ASSERT_STREQ("none", wfd_log_level_tostring(WFD_LOGLEVEL_NONE));
ASSERT_STREQ("fatal", wfd_log_level_tostring(WFD_LOGLEVEL_FATAL));
ASSERT_STREQ("error", wfd_log_level_tostring(WFD_LOGLEVEL_ERROR));
ASSERT_STREQ("warn", wfd_log_level_tostring(WFD_LOGLEVEL_WARN));
ASSERT_STREQ("info", wfd_log_level_tostring(WFD_LOGLEVEL_INFO));
ASSERT_STREQ("debug", wfd_log_level_tostring(WFD_LOGLEVEL_DEBUG));
ASSERT_STREQ("all", wfd_log_level_tostring(WFD_LOGLEVEL_ALL));
ASSERT_STREQ("<unknown>", wfd_log_level_tostring(42));
}

10
test/test_log_manager.cc Normal file
View File

@ -0,0 +1,10 @@
#include "webfused/log/manager.h"
#include "webfused/log/log.h"
#include <gtest/gtest.h>
#include <stddef.h>
TEST(log_manager, set_logger_fail_unknown_provider)
{
ASSERT_FALSE(wfd_log_manager_set_logger("unknown", WFD_LOGLEVEL_ALL, NULL));
}

View File

@ -0,0 +1,135 @@
#include <gtest/gtest.h>
#include "webfused/mountpoint_factory.h"
#include <webfuse/adapter/mountpoint.h>
#include <cstring>
TEST(mountpoint_factory, create)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfused_test");
ASSERT_TRUE(success);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem_fail_to_add_twice)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfused_test");
ASSERT_TRUE(success);
success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfused_test");
ASSERT_FALSE(success);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem_multi)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
for (size_t i = 0; i < 24; i++)
{
char name[10];
snprintf(name, 10, "test_%zu", i);
bool success = wfd_mountpoint_factory_add_filesystem(factory, name, "/tmp/webfused_test");
ASSERT_TRUE(success) << i;
}
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, add_filesystem_fail_invalid_path)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/do/not/allow/nested/paths");
ASSERT_FALSE(success);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test");
ASSERT_TRUE(success);
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_NE(nullptr, mountpoint);
ASSERT_STREQ("/tmp/webfuse_test", wf_mountpoint_get_path(mountpoint));
wf_mountpoint_dispose(mountpoint);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint_fail_already_in_use)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test");
ASSERT_TRUE(success);
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_NE(nullptr, mountpoint);
ASSERT_STREQ("/tmp/webfuse_test", wf_mountpoint_get_path(mountpoint));
wf_mountpoint * mountpoint2 = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_EQ(nullptr, mountpoint2);
wf_mountpoint_dispose(mountpoint);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint_fail_unknown_filesystem)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test");
ASSERT_TRUE(success);
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("unkown", factory);
ASSERT_EQ(nullptr, mountpoint);
wfd_mountpoint_factory_dispose(factory);
}
TEST(mountpiont_factory, create_mountpoint_multi)
{
wfd_mountpoint_factory * factory = wfd_mountpoint_factory_create();
ASSERT_NE(nullptr, factory);
bool success = wfd_mountpoint_factory_add_filesystem(factory, "test", "/tmp/webfuse_test");
ASSERT_TRUE(success);
for(int i = 0; i < 5; i++)
{
wf_mountpoint * mountpoint = wfd_mountpoint_factory_create_mountpoint("test", factory);
ASSERT_NE(nullptr, mountpoint) << i;
ASSERT_STREQ("/tmp/webfuse_test", wf_mountpoint_get_path(mountpoint)) << i;
wf_mountpoint_dispose(mountpoint);
}
wfd_mountpoint_factory_dispose(factory);
}

14
test/test_passwd.json Normal file
View File

@ -0,0 +1,14 @@
{
"meta": {
"type": "wf-userdb",
"major": 1,
"minor": 0,
"hash_algorithm": "sha512"
},
"users": {
"bob": {
"password_hash": "e51e27ce47054feead3d83068d47f2a07307d4877ac67da668ef43e0e466fe8c7b66651af14fdb8d48c51592ef5afa0c63f874d20861c6b9ef8e6513bfcaa330",
"salt": "b3be6979921edecfea88c50d0d1ec40b7f8c383831b2276c65969ead18e47c03"
}
}
}

90
test/test_settings.cc Normal file
View File

@ -0,0 +1,90 @@
#include <gtest/gtest.h>
#include "webfused/config/settings_intern.h"
#include "webfused/config/settings.h"
#include <libconfig.h>
TEST(settings, get_string)
{
char const settings_text[] =
"settings:\n"
"{\n"
" string_value = \"some.string\"\n"
" int_value = 42\n"
"}\n"
;
config_t config;
config_init(&config);
int rc = config_read_string(&config, settings_text);
ASSERT_TRUE(CONFIG_TRUE == rc);
config_setting_t * setting = config_lookup(&config, "settings");
ASSERT_NE(nullptr, setting);
wfd_settings settings;
wfd_settings_init(&settings, setting);
ASSERT_STREQ("some.string", wfd_settings_get_string(&settings, "string_value"));
ASSERT_EQ(nullptr, wfd_settings_get_string(&settings, "int_value"));
ASSERT_EQ(nullptr, wfd_settings_get_string(&settings, "invalid_value"));
ASSERT_EQ(nullptr, wfd_settings_get_string(NULL, "invalid_value"));
wfd_settings_cleanup(&settings);
config_destroy(&config);
}
TEST(settings, get_string_or_default)
{
char const settings_text[] =
"settings:\n"
"{\n"
" string_value = \"some.string\"\n"
" int_value = 42\n"
"}\n"
;
config_t config;
config_init(&config);
int rc = config_read_string(&config, settings_text);
ASSERT_TRUE(CONFIG_TRUE == rc);
config_setting_t * setting = config_lookup(&config, "settings");
ASSERT_NE(nullptr, setting);
wfd_settings settings;
wfd_settings_init(&settings, setting);
ASSERT_STREQ("some.string", wfd_settings_get_string_or_default(&settings, "string_value", "default"));
ASSERT_STREQ("default", wfd_settings_get_string_or_default(&settings, "int_value", "default"));
ASSERT_STREQ("default", wfd_settings_get_string_or_default(&settings, "invalid_value", "default"));
ASSERT_STREQ("default", wfd_settings_get_string_or_default(NULL, "invalid_value", "default"));
wfd_settings_cleanup(&settings);
config_destroy(&config);
}
TEST(settings, get_bool)
{
char const settings_text[] =
"settings:\n"
"{\n"
" true_value = true\n"
" false_value = false\n"
" int_value = 42\n"
"}\n"
;
config_t config;
config_init(&config);
int rc = config_read_string(&config, settings_text);
ASSERT_TRUE(CONFIG_TRUE == rc);
config_setting_t * setting = config_lookup(&config, "settings");
ASSERT_NE(nullptr, setting);
wfd_settings settings;
wfd_settings_init(&settings, setting);
ASSERT_TRUE(wfd_settings_get_bool(&settings, "true_value"));
ASSERT_FALSE(wfd_settings_get_bool(&settings, "false_value"));
ASSERT_FALSE(wfd_settings_get_bool(&settings, "int_value"));
ASSERT_FALSE(wfd_settings_get_bool(&settings, "invalid_value"));
ASSERT_FALSE(wfd_settings_get_bool(NULL, "invalid_value"));
wfd_settings_cleanup(&settings);
config_destroy(&config);
}

View File

@ -0,0 +1,27 @@
#include "webfused/log/stderr_logger.h"
#include "webfused/log/manager.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include <gtest/gtest.h>
#include <stddef.h>
TEST(stderr_logger, init)
{
ASSERT_TRUE(wfd_stderr_logger_init(WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(stderr_logger, init_via_manager)
{
ASSERT_TRUE(wfd_log_manager_set_logger("stderr", WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(stderr_logger, log)
{
ASSERT_TRUE(wfd_stderr_logger_init(WFD_LOGLEVEL_ALL, NULL));
WFD_INFO("some information");
wfd_logger_close();
}

View File

@ -0,0 +1,45 @@
#include "webfused/log/syslog_logger.h"
#include "webfused/log/manager.h"
#include "webfused/log/logger.h"
#include "webfused/log/log.h"
#include "mock_settings.hpp"
#include <gtest/gtest.h>
#include <stddef.h>
using ::webfused_test::MockSettings;
using ::testing::StrEq;
using ::testing::_;
using ::testing::Return;
TEST(syslog_logger, init)
{
ASSERT_TRUE(wfd_syslog_logger_init(WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(syslog_logger, init_fail_invalid_facility)
{
MockSettings settings;
EXPECT_CALL(settings, getStringOrDefault(StrEq("ident"), _)).Times(1).WillOnce(Return("webfused_test"));
EXPECT_CALL(settings, getStringOrDefault(StrEq("facility"), _)).Times(1).WillOnce(Return("invalid"));
EXPECT_CALL(settings, getBool(StrEq("log_pid"))).Times(1).WillOnce(Return(false));
wfd_settings * fake_settings = reinterpret_cast<wfd_settings*>(0xDEADBEEF);
ASSERT_FALSE(wfd_syslog_logger_init(WFD_LOGLEVEL_ALL, fake_settings));
}
TEST(syslog_logger, init_via_manager)
{
ASSERT_TRUE(wfd_log_manager_set_logger("syslog", WFD_LOGLEVEL_ALL, NULL));
wfd_logger_close();
}
TEST(syslog_logger, log)
{
ASSERT_TRUE(wfd_syslog_logger_init(WFD_LOGLEVEL_ALL, NULL));
WFD_INFO("some information");
wfd_logger_close();
}