Verified Commit b95798c6 authored by Sean Coughlin's avatar Sean Coughlin

Merge pull request #1037

1093d2b2 Tests: Integration: client instance test (oneiric)
3e148c2c Tests: Integration: add namespace header (oneiric)
dacbe518 Tests: Integration: add core status helpers (oneiric)
a9661a30 Client: Context: stop service when context stops (oneiric)
48c8b6c6 Tests: move python examples to integration tests (oneiric)
parents 3bacbd1a 1093d2b2
Pipeline #44696036 passed with stage
in 7 minutes and 10 seconds
......@@ -55,6 +55,7 @@ option(WITH_STATIC_DEPS "Static build with static dependencies" OFF)
option(WITH_SHARED_DEPS "Dynamic build with partial in-tree shared dependencies" OFF)
option(WITH_TESTS "Build unit tests" OFF)
option(WITH_FUZZ_TESTS "Build fuzz tests" OFF)
option(WITH_INTEGRATION_TESTS "Build integration tests" OFF)
option(WITH_COTIRE "Enable cotire (compile time reducer) - precompiled header and single compilation unit builds" ${MSVC})
# Verbosity enabled by default, but can be disabled from cli by adding -DCMAKE_VERBOSE_MAKEFILE=OFF
# https://github.com/monero-project/kovri/pull/867#discussion_r184359361
......@@ -389,6 +390,7 @@ message(STATUS " STATIC DEPS BUILD: ${WITH_STATIC_DEPS}")
message(STATUS " SHARED DEPS BUILD: ${WITH_SHARED_DEPS}")
message(STATUS " TESTS : ${WITH_TESTS}")
message(STATUS " FUZZ TESTS : ${WITH_FUZZ_TESTS}")
message(STATUS " INTEGRATION TESTS: ${WITH_INTEGRATION_TESTS}")
message(STATUS " Cotire : ${WITH_COTIRE}")
message(STATUS "---------------------------------------")
......@@ -402,6 +404,7 @@ if (WITH_TESTS)
add_subdirectory(tests/unit_tests)
endif()
if (WITH_PYTHON)
add_subdirectory(contrib/python)
if (WITH_INTEGRATION_TESTS)
target_compile_definitions(kovri-private INTERFACE WITH_INTEGRATION_TESTS)
add_subdirectory(tests/integration_tests)
endif()
......@@ -74,6 +74,7 @@ cmake-optimize = -D WITH_OPTIMIZE=ON
cmake-hardening = -D WITH_HARDENING=ON
cmake-tests = -D WITH_TESTS=ON
cmake-fuzz-tests = -D WITH_FUZZ_TESTS=ON
cmake-integ-tests= -D WITH_INTEGRATION_TESTS=ON
cmake-static = -D WITH_STATIC=ON
cmake-static-deps= -D WITH_STATIC_DEPS=ON
cmake-shared-deps= -D WITH_SHARED_DEPS=ON
......@@ -366,6 +367,11 @@ fuzz-tests: deps
$(eval cmake-kovri += $(cmake-debug) $(cmake-fuzz-tests))
$(call CMAKE,$(build),$(cmake-kovri)) && $(MAKE) -C $(build) $(cmake_target)
# Produce integration-tests
integration-tests: shared-deps
$(eval cmake-kovri += $(cmake-debug) $(cmake-integ-tests) $(cmake-python))
$(call CMAKE,$(build),$(cmake-kovri)) && $(MAKE) -C $(build) $(cmake_target)
# Produce Doxygen documentation
doxygen:
$(eval cmake-kovri += $(cmake) $(cmake-doxygen))
......
[unittest]
plugins = nose2.plugins.layers
......@@ -55,10 +55,6 @@ ClientContext::ClientContext()
m_I2PControlService(nullptr),
m_Exception(__func__) {}
ClientContext::~ClientContext() {
m_Service.stop();
}
// TODO(anonimal): nearly all Start/Stop handlers throughout the code-base should be replaced with proper RAII
void ClientContext::Start() {
if (!m_SharedLocalDestination) {
......@@ -122,6 +118,7 @@ void ClientContext::Stop() {
it.second->Stop();
m_Destinations.clear();
m_SharedLocalDestination = nullptr;
m_Service.stop();
}
void ClientContext::RequestShutdown() {
......
......@@ -54,7 +54,6 @@ namespace client {
class ClientContext {
public:
ClientContext();
~ClientContext();
void Start();
void Stop();
......
......@@ -36,6 +36,12 @@
#include "core/util/config.h"
#include "core/util/exception.h"
#if defined(WITH_INTEGRATION_TESTS)
#include "core/router/net_db/impl.h"
#include "core/router/tunnel/impl.h"
#include "core/router/transports/impl.h"
#endif
namespace kovri
{
......@@ -68,6 +74,13 @@ class Instance
return m_Config;
}
#if defined(WITH_INTEGRATION_TESTS)
bool is_running() const noexcept
{
return netdb.is_running() && tunnels.is_running() && transports.is_running();
}
#endif
private:
/// @brief Exception dispatcher
static core::Exception m_Exception;
......
......@@ -230,6 +230,13 @@ class NetDb : public NetDbTraits {
return m_LeaseSets.size();
}
#if defined(WITH_INTEGRATION_TESTS)
bool is_running() const noexcept
{
return m_IsRunning;
}
#endif
private:
bool CreateNetDb(boost::filesystem::path directory);
/// @brief Loads RI's from disk
......
......@@ -212,6 +212,13 @@ class Transports : public core::RouterInfoTraits {
std::string GetFormattedSessionInfo(
std::shared_ptr<const kovri::core::RouterInfo>& router) const;
#if defined(WITH_INTEGRATION_TESTS)
bool is_running() const noexcept
{
return m_IsRunning;
}
#endif
private:
void Run();
......
......@@ -287,6 +287,13 @@ class Tunnels {
void StopTunnelPool(
std::shared_ptr<TunnelPool> pool);
#if defined(WITH_INTEGRATION_TESTS)
bool is_running() const noexcept
{
return m_IsRunning;
}
#endif
private:
template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel(
......
#
# Copyright (c) 2015-2017, The Kovri I2P Router Project
# Copyright (c) 2015-2018, The Kovri I2P Router Project
#
# All rights reserved.
#
......@@ -29,27 +28,29 @@
#
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(kovri_python CXX)
project(kovri_integration CXX)
add_library(kovri_python SHARED
add_library(kovri_integration SHARED
kovri.cc
util.cc)
target_link_libraries(kovri_python PRIVATE kovri-private
target_link_libraries(kovri_integration PRIVATE kovri-private
${Boost_LIBRARIES} ${PYTHON_LIBRARIES})
# Use unity targets if they are available
foreach(_target IN ITEMS kovri-core kovri-client)
get_target_property(_unityTargetName ${_target} COTIRE_UNITY_TARGET_NAME)
if (_unityTargetName)
target_link_libraries(kovri_python PRIVATE ${_unityTargetName})
target_link_libraries(kovri_integration PRIVATE ${_unityTargetName})
else()
target_link_libraries(kovri_python PRIVATE ${_target})
target_link_libraries(kovri_integration PRIVATE ${_target})
endif()
endforeach()
set_target_properties(kovri_python PROPERTIES PREFIX "")
set_target_properties(kovri_integration PROPERTIES PREFIX "")
if (WITH_COTIRE)
cotire(kovri_python)
cotire(kovri_integration)
endif()
install(TARGETS kovri_integration LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR})
# Copyright (c) 2015-2018, The Kovri I2P Router Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
......@@ -43,7 +43,7 @@ import sys
sys.path.insert(0, root + "/build")
# Run kovri
import kovri_python as kovri
import kovri_integration as kovri
core = kovri.Core(args)
client = kovri.Client(core)
......
// Copyright (c) 2015-2017, The Kovri I2P Router Project
// Copyright (c) 2015-2018, The Kovri I2P Router Project
//
// All rights reserved.
//
......@@ -26,16 +26,19 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CONTRIB_PYTHON_INSTANCE_H_
#define CONTRIB_PYTHON_INSTANCE_H_
#ifndef TESTS_INTEGRATION_INSTANCE_H_
#define TESTS_INTEGRATION_INSTANCE_H_
#include "tests/integration_tests/namespace.h"
#include "tests/integration_tests/util.h"
#include <boost/python.hpp>
#include <string>
#include "src/client/instance.h"
#include "contrib/python/util.h"
#include "src/client/context.h"
/// @brief Wrapper for libcore instance
class Core final : public Util
......@@ -45,7 +48,7 @@ class Core final : public Util
: m_core(parse_string(args))
{
}
explicit Core(const boost::python::list& args) : m_core(parse_list(args)) {}
explicit Core(const py::list& args) : m_core(parse_list(args)) {}
~Core() {}
void init()
......@@ -63,14 +66,19 @@ class Core final : public Util
m_core.Stop();
}
bool is_running() const noexcept
{
return m_core.is_running();
}
// TODO(anonimal): upon further API development, we'll most likely want non-const reference
const kovri::core::Instance& get() const noexcept
const core::Instance& get() const noexcept
{
return m_core;
}
private:
kovri::core::Instance m_core;
core::Instance m_core;
};
/// @brief Wrapper for libclient instance
......@@ -90,13 +98,23 @@ class Client final
m_client.Start();
}
void reload()
{
m_client.Reload();
}
void stop()
{
m_client.Stop();
}
bool is_running() const noexcept
{
return !client::context.GetIoService().stopped();
}
private:
kovri::client::Instance m_client;
client::Instance m_client;
};
#endif // CONTRIB_PYTHON_INSTANCE_H_
#endif // TESTS_INTEGRATION_INSTANCE_H_
// Copyright (c) 2015-2017, The Kovri I2P Router Project
// Copyright (c) 2015-2018, The Kovri I2P Router Project
//
// All rights reserved.
//
......@@ -26,48 +26,28 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "contrib/python/instance.h"
#include "tests/integration_tests/namespace.h"
#include "tests/integration_tests/instance.h"
#include <boost/python.hpp>
#include "src/client/instance.h"
namespace py = boost::python;
void test_run()
{
kovri::core::Instance core;
kovri::client::Instance client(core);
client.Initialize();
client.Start();
client.Stop();
}
void wrapper_test_run()
{
Core core;
Client client(core);
client.init();
client.start();
client.stop();
}
// TODO(anonimal): in-tandem API development
BOOST_PYTHON_MODULE(kovri_python)
BOOST_PYTHON_MODULE(kovri_integration)
{
py::def("test_run", test_run);
py::def("wrapper_test_run", wrapper_test_run);
py::class_<Core>("Core", py::init<std::string>()) // string for convenience
.def(py::init<py::list>())
.def("init", &Core::init)
.def("start", &Core::start)
.def("stop", &Core::stop);
.def("stop", &Core::stop)
.def("is_running", &Core::is_running);
py::class_<Client>("Client", py::init<Core>())
.def("init", &Client::init)
.def("start", &Client::start)
.def("stop", &Client::stop);
.def("reload", &Client::reload)
.def("stop", &Client::stop)
.def("is_running", &Client::is_running);
}
/**
* Copyright (c) 2015-2018, The Kovri I2P Router Project
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TESTS_INTEGRATION_NAMESPACE_H_
#define TESTS_INTEGRATION_NAMESPACE_H_
// Add dummy namespaces to save on copy-pasta
namespace boost {
namespace python {}
} // namespace boost
namespace py = boost::python;
namespace kovri {
namespace core {
namespace crypto {}
} // namespace core
namespace client {}
} // namespace kovri
namespace client = kovri::client;
namespace core = kovri::core;
#endif
#!/usr/bin/env python
# Copyright (c) 2015-2018, The Kovri I2P Router Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from unittest2 import TestCase
from nose2.tools import such
with such.A("client instance w/ install setup") as it:
@it.has_test_setup
def setup(case):
"client instance test setup"
root = "."
args = "--log-level 5 --disable-ssu"
# Ensure kovri data dir is available
import subprocess
p = subprocess.Popen(['make', 'install'], cwd=root)
p.wait()
import sys
sys.path.insert(1, "./build")
# Use built kovri python object
import kovri_integration as kovri
it.core = kovri.Core(args)
it.client = kovri.Client(it.core)
@it.has_test_teardown
def teardown(case):
"client instance test teardown"
from os.path import expanduser
from shutil import rmtree
rmtree(expanduser('~') + "/.kovri")
def instance_dirs_exist():
from os.path import isdir, expanduser
ret = False
for _dir in ["client", "config", "core"]:
ret = isdir(expanduser("~") + "/.kovri/" + _dir)
if not ret: break
return ret
@it.should("init the client, start, reload, and stop")
def test(case):
try:
# Initialize the client
it.client.init()
# Check that instance directories exist
assert instance_dirs_exist()
# Start the client
it.client.start()
# Check the client is running
assert it.client.is_running() and it.core.is_running()
# Reload the client
it.client.reload()
# Check the client is running
assert it.client.is_running() and it.core.is_running()
# Stop the client
it.client.stop()
# Check the client is no longer running
assert not it.client.is_running() and not it.core.is_running()
except Exception as e:
print(str(e))
assert False
@it.should("throw when started without init")
def test(case):
try:
# Start the client
it.client.start()
# Test should fail if exception is not raised
assert False
except Exception:
# Expect an exception to be thrown
assert True
it.createTests(globals())
// Copyright (c) 2015-2017, The Kovri I2P Router Project
// Copyright (c) 2015-2018, The Kovri I2P Router Project
//
// All rights reserved.
//
......@@ -26,7 +26,7 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "contrib/python/util.h"
#include "tests/integration_tests/util.h"
#include <boost/python.hpp>
#include <boost/tokenizer.hpp>
......@@ -34,8 +34,6 @@
#include <string>
#include <vector>
namespace py = boost::python;
std::vector<std::string> Util::parse_string(const std::string& string)
{
std::vector<std::string> parsed;
......
// Copyright (c) 2015-2017, The Kovri I2P Router Project
// Copyright (c) 2015-2018, The Kovri I2P Router Project
//
// All rights reserved.
//
......@@ -26,8 +26,10 @@
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CONTRIB_PYTHON_UTIL_H_
#define CONTRIB_PYTHON_UTIL_H_
#ifndef TESTS_INTEGRATION_UTIL_H_
#define TESTS_INTEGRATION_UTIL_H_
#include "tests/integration_tests/namespace.h"
#include <boost/python.hpp>
#include <boost/tokenizer.hpp>
......@@ -46,7 +48,7 @@ struct Util
std::vector<std::string> parse_string(const std::string& string);
/// @brief Parse python list, store in vector
std::vector<std::string> parse_list(const boost::python::list& list);
std::vector<std::string> parse_list(const py::list& list);
};
#endif // CONTRIB_PYTHON_UTIL_H_
#endif // TESTS_INTEGRATION_UTIL_H_
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment