Merge branch 'master' into fix-commit-if-sync-replica-down
This commit is contained in:
commit
15afb4b5c2
@ -24,14 +24,6 @@ for file in $modified_files; do
|
|||||||
|
|
||||||
git checkout-index --prefix="$tmpdir/" -- $file
|
git checkout-index --prefix="$tmpdir/" -- $file
|
||||||
|
|
||||||
echo "Running clang-format..."
|
|
||||||
$project_folder/tools/git-clang-format $tmpdir/$file
|
|
||||||
CODE=$?
|
|
||||||
|
|
||||||
if [ $CODE -ne 0 ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Do not break header checker
|
# Do not break header checker
|
||||||
echo "Running header checker..."
|
echo "Running header checker..."
|
||||||
$project_folder/tools/header-checker.py $tmpdir/$file $file --amend-year
|
$project_folder/tools/header-checker.py $tmpdir/$file $file --amend-year
|
||||||
@ -39,7 +31,6 @@ for file in $modified_files; do
|
|||||||
if [ $CODE -ne 0 ]; then
|
if [ $CODE -ne 0 ]; then
|
||||||
FAIL=1
|
FAIL=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done;
|
done;
|
||||||
|
|
||||||
return ${FAIL}
|
return ${FAIL}
|
||||||
|
24
.pre-commit-config.yaml
Normal file
24
.pre-commit-config.yaml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v2.3.0
|
||||||
|
hooks:
|
||||||
|
- id: check-yaml
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 22.3.0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
args: # arguments to configure black
|
||||||
|
- --line-length=120
|
||||||
|
- --include='\.pyi?$'
|
||||||
|
# these folders wont be formatted by black
|
||||||
|
- --exclude="""\.git |
|
||||||
|
\.__pycache__|
|
||||||
|
build|
|
||||||
|
libs|
|
||||||
|
.cache"""
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: v13.0.0
|
||||||
|
hooks:
|
||||||
|
- id: clang-format
|
@ -47,6 +47,14 @@ modifications:
|
|||||||
value: ""
|
value: ""
|
||||||
override: false
|
override: false
|
||||||
|
|
||||||
|
- name: "bolt_cert_file"
|
||||||
|
value: "/etc/memgraph/ssl/cert.pem"
|
||||||
|
override: false
|
||||||
|
|
||||||
|
- name: "bolt_key_file"
|
||||||
|
value: "/etc/memgraph/ssl/key.pem"
|
||||||
|
override: false
|
||||||
|
|
||||||
- name: "storage_properties_on_edges"
|
- name: "storage_properties_on_edges"
|
||||||
value: "true"
|
value: "true"
|
||||||
override: true
|
override: true
|
||||||
|
@ -1559,7 +1559,7 @@ enum mgp_error mgp_func_add_opt_arg(struct mgp_func *func, const char *name, str
|
|||||||
typedef void (*mgp_func_cb)(struct mgp_list *, struct mgp_func_context *, struct mgp_func_result *,
|
typedef void (*mgp_func_cb)(struct mgp_list *, struct mgp_func_context *, struct mgp_func_result *,
|
||||||
struct mgp_memory *);
|
struct mgp_memory *);
|
||||||
|
|
||||||
/// Register a Memgraph magic function
|
/// Register a Memgraph magic function.
|
||||||
///
|
///
|
||||||
/// The `name` must be a sequence of digits, underscores, lowercase and
|
/// The `name` must be a sequence of digits, underscores, lowercase and
|
||||||
/// uppercase Latin letters. The name must begin with a non-digit character.
|
/// uppercase Latin letters. The name must begin with a non-digit character.
|
||||||
|
@ -1179,16 +1179,15 @@ def read_proc(func: typing.Callable[..., Record]):
|
|||||||
"""
|
"""
|
||||||
Register `func` as a read-only procedure of the current module.
|
Register `func` as a read-only procedure of the current module.
|
||||||
|
|
||||||
`read_proc` is meant to be used as a decorator function to register module
|
The decorator `read_proc` is meant to be used to register module procedures.
|
||||||
procedures. The registered `func` needs to be a callable which optionally
|
The registered `func` needs to be a callable which optionally takes
|
||||||
takes `ProcCtx` as the first argument. Other arguments of `func` will be
|
`ProcCtx` as its first argument. Other arguments of `func` will be bound to
|
||||||
bound to values passed in the cypherQuery. The full signature of `func`
|
values passed in the cypherQuery. The full signature of `func` needs to be
|
||||||
needs to be annotated with types. The return type must be
|
annotated with types. The return type must be `Record(field_name=type, ...)`
|
||||||
`Record(field_name=type, ...)` and the procedure must produce either a
|
and the procedure must produce either a complete Record or None. To mark a
|
||||||
complete Record or None. To mark a field as deprecated, use
|
field as deprecated, use `Record(field_name=Deprecated(type), ...)`.
|
||||||
`Record(field_name=Deprecated(type), ...)`. Multiple records can be
|
Multiple records can be produced by returning an iterable of them.
|
||||||
produced by returning an iterable of them. Registering generator functions
|
Registering generator functions is currently not supported.
|
||||||
is currently not supported.
|
|
||||||
|
|
||||||
Example usage.
|
Example usage.
|
||||||
|
|
||||||
@ -1222,16 +1221,16 @@ def write_proc(func: typing.Callable[..., Record]):
|
|||||||
"""
|
"""
|
||||||
Register `func` as a writeable procedure of the current module.
|
Register `func` as a writeable procedure of the current module.
|
||||||
|
|
||||||
`write_proc` is meant to be used as a decorator function to register module
|
The decorator `write_proc` is meant to be used to register module
|
||||||
procedures. The registered `func` needs to be a callable which optionally
|
procedures. The registered `func` needs to be a callable which optionally
|
||||||
takes `ProcCtx` as the first argument. Other arguments of `func` will be
|
takes `ProcCtx` as the first argument. Other arguments of `func` will be
|
||||||
bound to values passed in the cypherQuery. The full signature of `func`
|
bound to values passed in the cypherQuery. The full signature of `func`
|
||||||
needs to be annotated with types. The return type must be
|
needs to be annotated with types. The return type must be
|
||||||
`Record(field_name=type, ...)` and the procedure must produce either a
|
`Record(field_name=type, ...)` and the procedure must produce either a
|
||||||
complete Record or None. To mark a field as deprecated, use
|
complete Record or None. To mark a field as deprecated, use
|
||||||
`Record(field_name=Deprecated(type), ...)`. Multiple records can be
|
`Record(field_name=Deprecated(type), ...)`. Multiple records can be produced
|
||||||
produced by returning an iterable of them. Registering generator functions
|
by returning an iterable of them. Registering generator functions is
|
||||||
is currently not supported.
|
currently not supported.
|
||||||
|
|
||||||
Example usage.
|
Example usage.
|
||||||
|
|
||||||
@ -1459,8 +1458,9 @@ def transformation(func: typing.Callable[..., Record]):
|
|||||||
class FuncCtx:
|
class FuncCtx:
|
||||||
"""Context of a function being executed.
|
"""Context of a function being executed.
|
||||||
|
|
||||||
Access to a FuncCtx is only valid during a single execution of a transformation.
|
Access to a FuncCtx is only valid during a single execution of a function in
|
||||||
You should not globally store a FuncCtx instance.
|
a query. You should not globally store a FuncCtx instance. The graph object
|
||||||
|
within the FuncCtx is not mutable.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__slots__ = "_graph"
|
__slots__ = "_graph"
|
||||||
@ -1475,6 +1475,45 @@ class FuncCtx:
|
|||||||
|
|
||||||
|
|
||||||
def function(func: typing.Callable):
|
def function(func: typing.Callable):
|
||||||
|
"""
|
||||||
|
Register `func` as a user-defined function in the current module.
|
||||||
|
|
||||||
|
The decorator `function` is meant to be used to register module functions.
|
||||||
|
The registered `func` needs to be a callable which optionally takes
|
||||||
|
`FuncCtx` as its first argument. Other arguments of `func` will be bound to
|
||||||
|
values passed in the Cypher query. Only the funcion arguments need to be
|
||||||
|
annotated with types. The return type doesn't need to be specified, but it
|
||||||
|
has to be supported by `mgp.Any`. Registering generator functions is
|
||||||
|
currently not supported.
|
||||||
|
|
||||||
|
Example usage.
|
||||||
|
|
||||||
|
```
|
||||||
|
import mgp
|
||||||
|
@mgp.function
|
||||||
|
def func_example(context: mgp.FuncCtx,
|
||||||
|
required_arg: str,
|
||||||
|
optional_arg: mgp.Nullable[str] = None
|
||||||
|
):
|
||||||
|
return_args = [required_arg]
|
||||||
|
if optional_arg is not None:
|
||||||
|
return_args.append(optional_arg)
|
||||||
|
# Return any kind of result supported by mgp.Any
|
||||||
|
return return_args
|
||||||
|
```
|
||||||
|
|
||||||
|
The example function above returns a list of provided arguments:
|
||||||
|
* `required_arg` is always present and its value is the first argument of
|
||||||
|
the function.
|
||||||
|
* `optional_arg` is present if the second argument of the function is not
|
||||||
|
`null`.
|
||||||
|
Any errors can be reported by raising an Exception.
|
||||||
|
|
||||||
|
The function can be invoked in Cypher using the following calls:
|
||||||
|
RETURN example.func_example("first argument", "second_argument");
|
||||||
|
RETURN example.func_example("first argument");
|
||||||
|
Naturally, you may pass in different arguments.
|
||||||
|
"""
|
||||||
raise_if_does_not_meet_requirements(func)
|
raise_if_does_not_meet_requirements(func)
|
||||||
register_func = _mgp.Module.add_function
|
register_func = _mgp.Module.add_function
|
||||||
sig = inspect.signature(func)
|
sig = inspect.signature(func)
|
||||||
|
4
init
4
init
@ -135,3 +135,7 @@ for hook in $(find $DIR/.githooks -type f -printf "%f\n"); do
|
|||||||
ln -s -f "$DIR/.githooks/$hook" "$DIR/.git/hooks/$hook"
|
ln -s -f "$DIR/.githooks/$hook" "$DIR/.git/hooks/$hook"
|
||||||
echo "Added $hook hook"
|
echo "Added $hook hook"
|
||||||
done;
|
done;
|
||||||
|
|
||||||
|
# Install precommit hook
|
||||||
|
python3 -m pip install pre-commit
|
||||||
|
python3 -m pre_commit install
|
||||||
|
@ -41,7 +41,7 @@ set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}
|
|||||||
applications driver by real-time connected data.")
|
applications driver by real-time connected data.")
|
||||||
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
||||||
# We also depend on `python3` because we embed it in Memgraph.
|
# We also depend on `python3` because we embed it in Memgraph.
|
||||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl (>= 1.1.0), python3 (>= 3.5.0)")
|
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl (>= 1.1.0), python3 (>= 3.5.0), libstdc++6")
|
||||||
|
|
||||||
# Setting arhitecture extension for rpm packages
|
# Setting arhitecture extension for rpm packages
|
||||||
set(MG_ARCH_EXTENSION_RPM "noarch")
|
set(MG_ARCH_EXTENSION_RPM "noarch")
|
||||||
@ -67,7 +67,7 @@ It aims to deliver developers the speed, simplicity and scale required to build
|
|||||||
the next generation of applications driver by real-time connected data.")
|
the next generation of applications driver by real-time connected data.")
|
||||||
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
# Add `openssl` package to dependencies list. Used to generate SSL certificates.
|
||||||
# We also depend on `python3` because we embed it in Memgraph.
|
# We also depend on `python3` because we embed it in Memgraph.
|
||||||
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0")
|
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.0.0, curl >= 7.29.0, python3 >= 3.5.0, libstdc >= 6")
|
||||||
|
|
||||||
# All variables must be set before including.
|
# All variables must be set before including.
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
@ -246,11 +246,7 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
Session(Session &&) = delete;
|
Session(Session &&) = delete;
|
||||||
Session &operator=(const Session &) = delete;
|
Session &operator=(const Session &) = delete;
|
||||||
Session &operator=(Session &&) = delete;
|
Session &operator=(Session &&) = delete;
|
||||||
~Session() {
|
~Session() = default;
|
||||||
if (IsConnected()) {
|
|
||||||
spdlog::error("Session: Destructor called while execution is active");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Start() {
|
bool Start() {
|
||||||
if (execution_active_) {
|
if (execution_active_) {
|
||||||
@ -400,7 +396,6 @@ class Session final : public std::enable_shared_from_this<Session<TSession, TSes
|
|||||||
if (ec == boost::asio::error::operation_aborted) {
|
if (ec == boost::asio::error::operation_aborted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
execution_active_ = false;
|
|
||||||
|
|
||||||
if (ec == boost::asio::error::eof) {
|
if (ec == boost::asio::error::eof) {
|
||||||
spdlog::info("Session closed by peer");
|
spdlog::info("Session closed by peer");
|
||||||
|
@ -1070,6 +1070,22 @@ int main(int argc, char **argv) {
|
|||||||
if (maybe_exc) {
|
if (maybe_exc) {
|
||||||
spdlog::error(memgraph::utils::MessageWithLink("Unable to load support for embedded Python: {}.", *maybe_exc,
|
spdlog::error(memgraph::utils::MessageWithLink("Unable to load support for embedded Python: {}.", *maybe_exc,
|
||||||
"https://memgr.ph/python"));
|
"https://memgr.ph/python"));
|
||||||
|
} else {
|
||||||
|
// Change how we load dynamic libraries on Python by using RTLD_NOW and
|
||||||
|
// RTLD_DEEPBIND flags. This solves an issue with using the wrong version of
|
||||||
|
// libstd.
|
||||||
|
auto gil = memgraph::py::EnsureGIL();
|
||||||
|
// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
||||||
|
auto *flag = PyLong_FromLong(RTLD_NOW | RTLD_DEEPBIND);
|
||||||
|
auto *setdl = PySys_GetObject("setdlopenflags");
|
||||||
|
MG_ASSERT(setdl);
|
||||||
|
auto *arg = PyTuple_New(1);
|
||||||
|
MG_ASSERT(arg);
|
||||||
|
MG_ASSERT(PyTuple_SetItem(arg, 0, flag) == 0);
|
||||||
|
PyObject_CallObject(setdl, arg);
|
||||||
|
Py_DECREF(flag);
|
||||||
|
Py_DECREF(setdl);
|
||||||
|
Py_DECREF(arg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
spdlog::error(
|
spdlog::error(
|
||||||
|
@ -822,7 +822,8 @@ bool SharedLibraryModule::Load(const std::filesystem::path &file_path) {
|
|||||||
spdlog::info("Loading module {}...", file_path);
|
spdlog::info("Loading module {}...", file_path);
|
||||||
file_path_ = file_path;
|
file_path_ = file_path;
|
||||||
dlerror(); // Clear any existing error.
|
dlerror(); // Clear any existing error.
|
||||||
handle_ = dlopen(file_path.c_str(), RTLD_NOW | RTLD_LOCAL);
|
// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
||||||
|
handle_ = dlopen(file_path.c_str(), RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND);
|
||||||
if (!handle_) {
|
if (!handle_) {
|
||||||
spdlog::error(
|
spdlog::error(
|
||||||
utils::MessageWithLink("Unable to load module {}; {}.", file_path, dlerror(), "https://memgr.ph/modules"));
|
utils::MessageWithLink("Unable to load module {}; {}.", file_path, dlerror(), "https://memgr.ph/modules"));
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
/// API for loading and registering modules providing custom oC procedures
|
/// API for loading and registering modules providing custom oC procedures
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -128,6 +129,40 @@ class ModuleRegistry final {
|
|||||||
const std::filesystem::path &InternalModuleDir() const noexcept;
|
const std::filesystem::path &InternalModuleDir() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class SharedLibraryHandle {
|
||||||
|
public:
|
||||||
|
SharedLibraryHandle(const std::string &shared_library, int mode) : handle_{dlopen(shared_library.c_str(), mode)} {}
|
||||||
|
SharedLibraryHandle(const SharedLibraryHandle &) = delete;
|
||||||
|
SharedLibraryHandle(SharedLibraryHandle &&) = delete;
|
||||||
|
SharedLibraryHandle operator=(const SharedLibraryHandle &) = delete;
|
||||||
|
SharedLibraryHandle operator=(SharedLibraryHandle &&) = delete;
|
||||||
|
|
||||||
|
~SharedLibraryHandle() {
|
||||||
|
if (handle_) {
|
||||||
|
dlclose(handle_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if __has_feature(address_sanitizer)
|
||||||
|
// This is why we need RTLD_NODELETE and we must not use RTLD_DEEPBIND with
|
||||||
|
// ASAN: https://github.com/google/sanitizers/issues/89
|
||||||
|
SharedLibraryHandle libstd_handle{"libstdc++.so.6", RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE};
|
||||||
|
#else
|
||||||
|
// The reason behind opening share library during runtime is to avoid issues
|
||||||
|
// with loading symbols from stdlib. We have encounter issues with locale
|
||||||
|
// that cause std::cout not being printed and issues when python libraries
|
||||||
|
// would call stdlib (e.g. pytorch).
|
||||||
|
// The way that those issues were solved was
|
||||||
|
// by using RTLD_DEEPBIND. RTLD_DEEPBIND ensures that the lookup for the
|
||||||
|
// mentioned library will be first performed in the already existing binded
|
||||||
|
// libraries and then the global namespace.
|
||||||
|
// RTLD_DEEPBIND => https://linux.die.net/man/3/dlopen
|
||||||
|
SharedLibraryHandle libstd_handle{"libstdc++.so.6", RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND};
|
||||||
|
#endif
|
||||||
std::vector<std::filesystem::path> modules_dirs_;
|
std::vector<std::filesystem::path> modules_dirs_;
|
||||||
std::filesystem::path internal_module_dir_;
|
std::filesystem::path internal_module_dir_;
|
||||||
};
|
};
|
||||||
|
@ -22,6 +22,7 @@ add_custom_target(memgraph__e2e__${TARGET_PREFIX}__${FILE_NAME} ALL
|
|||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE_NAME})
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${FILE_NAME})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
add_subdirectory(server)
|
||||||
add_subdirectory(replication)
|
add_subdirectory(replication)
|
||||||
add_subdirectory(memory)
|
add_subdirectory(memory)
|
||||||
add_subdirectory(triggers)
|
add_subdirectory(triggers)
|
||||||
@ -31,6 +32,8 @@ add_subdirectory(temporal_types)
|
|||||||
add_subdirectory(write_procedures)
|
add_subdirectory(write_procedures)
|
||||||
add_subdirectory(magic_functions)
|
add_subdirectory(magic_functions)
|
||||||
add_subdirectory(module_file_manager)
|
add_subdirectory(module_file_manager)
|
||||||
add_subdirectory(websocket)
|
add_subdirectory(monitoring_server)
|
||||||
|
|
||||||
copy_e2e_python_files(pytest_runner pytest_runner.sh "")
|
copy_e2e_python_files(pytest_runner pytest_runner.sh "")
|
||||||
|
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.crt DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.key DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
8
tests/e2e/monitoring_server/CMakeLists.txt
Normal file
8
tests/e2e/monitoring_server/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
find_package(gflags REQUIRED)
|
||||||
|
find_package(Boost REQUIRED)
|
||||||
|
|
||||||
|
add_executable(memgraph__e2e__monitoring_server monitoring.cpp)
|
||||||
|
target_link_libraries(memgraph__e2e__monitoring_server mgclient mg-utils json gflags Boost::headers)
|
||||||
|
|
||||||
|
add_executable(memgraph__e2e__monitoring_server_ssl monitoring_ssl.cpp)
|
||||||
|
target_link_libraries(memgraph__e2e__monitoring_server_ssl mgclient mg-utils json gflags Boost::headers)
|
@ -1,15 +1,15 @@
|
|||||||
cert_file: &cert_file "$PROJECT_DIR/tests/e2e/websocket/memgraph-selfsigned.crt"
|
cert_file: &cert_file "$PROJECT_DIR/tests/e2e/memgraph-selfsigned.crt"
|
||||||
key_file: &key_file "$PROJECT_DIR/tests/e2e/websocket/memgraph-selfsigned.key"
|
key_file: &key_file "$PROJECT_DIR/tests/e2e/memgraph-selfsigned.key"
|
||||||
bolt_port: &bolt_port "7687"
|
bolt_port: &bolt_port "7687"
|
||||||
monitoring_port: &monitoring_port "7444"
|
monitoring_port: &monitoring_port "7444"
|
||||||
template_cluster: &template_cluster
|
template_cluster: &template_cluster
|
||||||
cluster:
|
cluster:
|
||||||
websocket:
|
monitoring:
|
||||||
args: ["--bolt-port=7687", "--log-level=TRACE", "--"]
|
args: ["--bolt-port=7687", "--log-level=TRACE", "--"]
|
||||||
log_file: "websocket-e2e.log"
|
log_file: "monitoring-websocket-e2e.log"
|
||||||
template_cluster_ssl: &template_cluster_ssl
|
template_cluster_ssl: &template_cluster_ssl
|
||||||
cluster:
|
cluster:
|
||||||
websocket:
|
monitoring:
|
||||||
args:
|
args:
|
||||||
[
|
[
|
||||||
"--bolt-port",
|
"--bolt-port",
|
||||||
@ -23,16 +23,15 @@ template_cluster_ssl: &template_cluster_ssl
|
|||||||
*key_file,
|
*key_file,
|
||||||
"--",
|
"--",
|
||||||
]
|
]
|
||||||
log_file: "websocket-ssl-e2e.log"
|
log_file: "monitoring-websocket-ssl-e2e.log"
|
||||||
ssl: true
|
ssl: true
|
||||||
|
|
||||||
workloads:
|
workloads:
|
||||||
- name: "Websocket"
|
- name: "Monitoring server using WebSocket"
|
||||||
binary: "tests/e2e/websocket/memgraph__e2e__websocket"
|
binary: "tests/e2e/monitoring_server/memgraph__e2e__monitoring_server"
|
||||||
args: ["--bolt-port", *bolt_port, "--monitoring-port", *monitoring_port]
|
args: ["--bolt-port", *bolt_port, "--monitoring-port", *monitoring_port]
|
||||||
<<: *template_cluster
|
<<: *template_cluster
|
||||||
- name: "Websocket SSL"
|
- name: "Monitoring server using WebSocket SSL"
|
||||||
binary: "tests/e2e/websocket/memgraph__e2e__websocket_ssl"
|
binary: "tests/e2e/monitoring_server/memgraph__e2e__monitoring_server_ssl"
|
||||||
args: ["--bolt-port", *bolt_port, "--monitoring-port", *monitoring_port]
|
args: ["--bolt-port", *bolt_port, "--monitoring-port", *monitoring_port]
|
||||||
<<: *template_cluster_ssl
|
<<: *template_cluster_ssl
|
||||||
|
|
8
tests/e2e/server/CMakeLists.txt
Normal file
8
tests/e2e/server/CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
find_package(gflags REQUIRED)
|
||||||
|
find_package(Boost REQUIRED)
|
||||||
|
|
||||||
|
add_executable(memgraph__e2e__server_connection server_connection.cpp)
|
||||||
|
target_link_libraries(memgraph__e2e__server_connection mgclient mg-utils gflags)
|
||||||
|
|
||||||
|
add_executable(memgraph__e2e__server_ssl_connection server_ssl_connection.cpp)
|
||||||
|
target_link_libraries(memgraph__e2e__server_ssl_connection mgclient mg-utils gflags)
|
60
tests/e2e/server/common.hpp
Normal file
60
tests/e2e/server/common.hpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2022 Memgraph Ltd.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
// License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// licenses/APL.txt.
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/asio/steady_timer.hpp>
|
||||||
|
#include <boost/system/detail/error_code.hpp>
|
||||||
|
#include <mgclient.hpp>
|
||||||
|
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
|
inline void OnTimeoutExpiration(const boost::system::error_code &ec) {
|
||||||
|
// Timer was not cancelled, take necessary action.
|
||||||
|
MG_ASSERT(!!ec, "Connection timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void EstablishConnection(const uint16_t bolt_port, const bool use_ssl) {
|
||||||
|
spdlog::info("Testing successfull connection from one client");
|
||||||
|
mg::Client::Init();
|
||||||
|
|
||||||
|
boost::asio::io_context ioc;
|
||||||
|
boost::asio::steady_timer timer(ioc, std::chrono::seconds(5));
|
||||||
|
timer.async_wait(std::bind_front(&OnTimeoutExpiration));
|
||||||
|
std::jthread bg_thread([&ioc]() { ioc.run(); });
|
||||||
|
|
||||||
|
auto client = mg::Client::Connect({.host = "127.0.0.1", .port = bolt_port, .use_ssl = use_ssl});
|
||||||
|
MG_ASSERT(client, "Failed to connect!");
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void EstablishMultipleConnections(const uint16_t bolt_port, const bool use_ssl) {
|
||||||
|
spdlog::info("Testing successfull connection from multiple clients");
|
||||||
|
mg::Client::Init();
|
||||||
|
|
||||||
|
boost::asio::io_context ioc;
|
||||||
|
boost::asio::steady_timer timer(ioc, std::chrono::seconds(5));
|
||||||
|
timer.async_wait(std::bind_front(&OnTimeoutExpiration));
|
||||||
|
std::jthread bg_thread([&ioc]() { ioc.run(); });
|
||||||
|
|
||||||
|
auto client1 = mg::Client::Connect({.host = "127.0.0.1", .port = bolt_port, .use_ssl = use_ssl});
|
||||||
|
auto client2 = mg::Client::Connect({.host = "127.0.0.1", .port = bolt_port, .use_ssl = use_ssl});
|
||||||
|
auto client3 = mg::Client::Connect({.host = "127.0.0.1", .port = bolt_port, .use_ssl = use_ssl});
|
||||||
|
|
||||||
|
MG_ASSERT(client1, "Failed to connect!");
|
||||||
|
MG_ASSERT(client2, "Failed to connect!");
|
||||||
|
MG_ASSERT(client3, "Failed to connect!");
|
||||||
|
timer.cancel();
|
||||||
|
}
|
56
tests/e2e/server/server_connection.cpp
Normal file
56
tests/e2e/server/server_connection.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright 2022 Memgraph Ltd.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
// License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// licenses/APL.txt.
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/asio/steady_timer.hpp>
|
||||||
|
#include <boost/system/detail/error_code.hpp>
|
||||||
|
#include <mgclient.hpp>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
|
DEFINE_uint64(bolt_port, 7687, "Bolt port");
|
||||||
|
|
||||||
|
void EstablishSSLConnectionToNonSSLServer(const auto bolt_port) {
|
||||||
|
spdlog::info("Testing that connection fails when connecting to non SSL server while using SSL");
|
||||||
|
mg::Client::Init();
|
||||||
|
|
||||||
|
boost::asio::io_context ioc;
|
||||||
|
boost::asio::steady_timer timer(ioc, std::chrono::seconds(5));
|
||||||
|
timer.async_wait(std::bind_front(&OnTimeoutExpiration));
|
||||||
|
std::jthread bg_thread([&ioc]() { ioc.run(); });
|
||||||
|
|
||||||
|
auto client = mg::Client::Connect({.host = "127.0.0.1", .port = bolt_port, .use_ssl = true});
|
||||||
|
|
||||||
|
MG_ASSERT(client == nullptr, "Connection not refused when connecting with SSL turned on to a non SSL server!");
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
google::SetUsageMessage("Memgraph E2E server connection!");
|
||||||
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
MG_ASSERT(FLAGS_bolt_port != 0);
|
||||||
|
memgraph::logging::RedirectToStderr();
|
||||||
|
|
||||||
|
const auto bolt_port = static_cast<uint16_t>(FLAGS_bolt_port);
|
||||||
|
|
||||||
|
EstablishConnection(bolt_port, false);
|
||||||
|
EstablishMultipleConnections(bolt_port, false);
|
||||||
|
EstablishSSLConnectionToNonSSLServer(bolt_port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
57
tests/e2e/server/server_ssl_connection.cpp
Normal file
57
tests/e2e/server/server_ssl_connection.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2022 Memgraph Ltd.
|
||||||
|
//
|
||||||
|
// Use of this software is governed by the Business Source License
|
||||||
|
// included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
// License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
//
|
||||||
|
// As of the Change Date specified in that file, in accordance with
|
||||||
|
// the Business Source License, use of this software will be governed
|
||||||
|
// by the Apache License, Version 2.0, included in the file
|
||||||
|
// licenses/APL.txt.
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <gflags/gflags.h>
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#include <boost/asio/steady_timer.hpp>
|
||||||
|
#include <boost/system/detail/error_code.hpp>
|
||||||
|
#include <mgclient.hpp>
|
||||||
|
|
||||||
|
#include "common.hpp"
|
||||||
|
#include "utils/logging.hpp"
|
||||||
|
|
||||||
|
DEFINE_uint64(bolt_port, 7687, "Bolt port");
|
||||||
|
|
||||||
|
void EstablishNonSSLConnectionToSSLServer(const auto bolt_port) {
|
||||||
|
spdlog::info("Testing that connection fails when connecting to SSL server without using SSL");
|
||||||
|
mg::Client::Init();
|
||||||
|
|
||||||
|
boost::asio::io_context ioc;
|
||||||
|
boost::asio::steady_timer timer(ioc, std::chrono::seconds(5));
|
||||||
|
timer.async_wait(std::bind_front(&OnTimeoutExpiration));
|
||||||
|
std::jthread bg_thread([&ioc]() { ioc.run(); });
|
||||||
|
|
||||||
|
auto client = mg::Client::Connect({.host = "127.0.0.1", .port = bolt_port, .use_ssl = false});
|
||||||
|
|
||||||
|
MG_ASSERT(client == nullptr, "Connection not refused when conneting without SSL turned on to a SSL server!");
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
google::SetUsageMessage("Memgraph E2E server SSL connection!");
|
||||||
|
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
MG_ASSERT(FLAGS_bolt_port != 0);
|
||||||
|
memgraph::logging::RedirectToStderr();
|
||||||
|
|
||||||
|
const auto bolt_port = static_cast<uint16_t>(FLAGS_bolt_port);
|
||||||
|
|
||||||
|
EstablishConnection(bolt_port, true);
|
||||||
|
EstablishMultipleConnections(bolt_port, true);
|
||||||
|
EstablishNonSSLConnectionToSSLServer(bolt_port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
34
tests/e2e/server/workloads.yaml
Normal file
34
tests/e2e/server/workloads.yaml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
cert_file: &cert_file "$PROJECT_DIR/tests/e2e/memgraph-selfsigned.crt"
|
||||||
|
key_file: &key_file "$PROJECT_DIR/tests/e2e/memgraph-selfsigned.key"
|
||||||
|
bolt_port: &bolt_port "7687"
|
||||||
|
template_cluster: &template_cluster
|
||||||
|
cluster:
|
||||||
|
server:
|
||||||
|
args: ["--bolt-port=7687", "--log-level=TRACE", "--"]
|
||||||
|
log_file: "server-connection-e2e.log"
|
||||||
|
template_cluster_ssl: &template_cluster_ssl
|
||||||
|
cluster:
|
||||||
|
server:
|
||||||
|
args:
|
||||||
|
[
|
||||||
|
"--bolt-port",
|
||||||
|
*bolt_port,
|
||||||
|
"--log-level=TRACE",
|
||||||
|
"--bolt-cert-file",
|
||||||
|
*cert_file,
|
||||||
|
"--bolt-key-file",
|
||||||
|
*key_file,
|
||||||
|
"--",
|
||||||
|
]
|
||||||
|
log_file: "server-connection-ssl-e2e.log"
|
||||||
|
ssl: true
|
||||||
|
|
||||||
|
workloads:
|
||||||
|
- name: "Server connection"
|
||||||
|
binary: "tests/e2e/server/memgraph__e2e__server_connection"
|
||||||
|
args: ["--bolt-port", *bolt_port]
|
||||||
|
<<: *template_cluster
|
||||||
|
- name: "Server SSL connection"
|
||||||
|
binary: "tests/e2e/server/memgraph__e2e__server_ssl_connection"
|
||||||
|
args: ["--bolt-port", *bolt_port]
|
||||||
|
<<: *template_cluster_ssl
|
8
tests/e2e/streams/README.md
Normal file
8
tests/e2e/streams/README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
There are three docker-compose files in this directory:
|
||||||
|
* [kafka.yml](kafka.yml)
|
||||||
|
* [pulsar.yml](pulsar.yml)
|
||||||
|
* [redpanda.yml](redpanda.yml)
|
||||||
|
|
||||||
|
To run one of them, use the `docker-compose -f <filename> up -V` command. Optionally you can append `-d` to detach from the started containers. You can stop the detach containers by `docker-compose -f <filename> down`.
|
||||||
|
|
||||||
|
If you experience strange errors, try to clean up the previously created containers by `docker-compose -f <filename> rm -svf`.
|
@ -1,13 +1,13 @@
|
|||||||
version: "3"
|
version: '3.7'
|
||||||
services:
|
services:
|
||||||
zookeeper:
|
zookeeper:
|
||||||
image: 'bitnami/zookeeper:3.6.3-debian-10-r33'
|
image: 'bitnami/zookeeper:latest'
|
||||||
ports:
|
ports:
|
||||||
- '2181:2181'
|
- '2181:2181'
|
||||||
environment:
|
environment:
|
||||||
- ALLOW_ANONYMOUS_LOGIN=yes
|
- ALLOW_ANONYMOUS_LOGIN=yes
|
||||||
kafka:
|
kafka:
|
||||||
image: 'bitnami/kafka:2.8.0-debian-10-r49'
|
image: 'bitnami/kafka:latest'
|
||||||
ports:
|
ports:
|
||||||
- '9092:9092'
|
- '9092:9092'
|
||||||
environment:
|
environment:
|
||||||
@ -18,9 +18,3 @@ services:
|
|||||||
- ALLOW_PLAINTEXT_LISTENER=yes
|
- ALLOW_PLAINTEXT_LISTENER=yes
|
||||||
depends_on:
|
depends_on:
|
||||||
- zookeeper
|
- zookeeper
|
||||||
pulsar:
|
|
||||||
image: 'apachepulsar/pulsar:2.8.1'
|
|
||||||
ports:
|
|
||||||
- '6652:8080'
|
|
||||||
- '6650:6650'
|
|
||||||
entrypoint: ['bin/pulsar', 'standalone']
|
|
8
tests/e2e/streams/pulsar.yml
Normal file
8
tests/e2e/streams/pulsar.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: '3.7'
|
||||||
|
services:
|
||||||
|
pulsar:
|
||||||
|
image: 'apachepulsar/pulsar:latest'
|
||||||
|
ports:
|
||||||
|
- '6652:8080'
|
||||||
|
- '6650:6650'
|
||||||
|
entrypoint: ['bin/pulsar', 'standalone']
|
23
tests/e2e/streams/redpanda.yml
Normal file
23
tests/e2e/streams/redpanda.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
version: '3.7'
|
||||||
|
services:
|
||||||
|
redpanda:
|
||||||
|
command:
|
||||||
|
- redpanda
|
||||||
|
- start
|
||||||
|
- --smp
|
||||||
|
- '1'
|
||||||
|
- --reserve-memory
|
||||||
|
- 0M
|
||||||
|
- --overprovisioned
|
||||||
|
- --node-id
|
||||||
|
- '0'
|
||||||
|
- --kafka-addr
|
||||||
|
- PLAINTEXT://0.0.0.0:29092,OUTSIDE://0.0.0.0:9092
|
||||||
|
- --advertise-kafka-addr
|
||||||
|
- PLAINTEXT://redpanda:29092,OUTSIDE://localhost:9092
|
||||||
|
# NOTE: Please use the latest version here!
|
||||||
|
image: docker.vectorized.io/vectorized/redpanda:latest
|
||||||
|
container_name: redpanda-1
|
||||||
|
ports:
|
||||||
|
- 9092:9092
|
||||||
|
- 29092:29092
|
@ -1,10 +0,0 @@
|
|||||||
find_package(gflags REQUIRED)
|
|
||||||
find_package(Boost REQUIRED)
|
|
||||||
|
|
||||||
add_executable(memgraph__e2e__websocket websocket.cpp)
|
|
||||||
target_link_libraries(memgraph__e2e__websocket mgclient mg-utils json gflags Boost::headers)
|
|
||||||
|
|
||||||
add_executable(memgraph__e2e__websocket_ssl websocket_ssl.cpp)
|
|
||||||
target_link_libraries(memgraph__e2e__websocket_ssl mgclient mg-utils json gflags Boost::headers)
|
|
||||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.crt DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
|
||||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/memgraph-selfsigned.key DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
|
Loading…
Reference in New Issue
Block a user