Skip to content

Commit

Permalink
Split up tests to run in parallel.
Browse files Browse the repository at this point in the history
  • Loading branch information
alamaison committed Jan 30, 2016
1 parent f2e1c12 commit 6d2a91d
Show file tree
Hide file tree
Showing 11 changed files with 2,211 additions and 1,943 deletions.
120 changes: 68 additions & 52 deletions test/ssh/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,80 +13,96 @@
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.

set(INTEGRATION_TESTS
auth_test.cpp
filesystem_test.cpp
host_key_test.cpp
hunter_add_package(Boost.Process)

# Underscores to distinguish from same-name Swish fixtures. Can be renamed when
# we split the projects.
add_library(openssh_fixture_
openssh_fixture.cpp
session_test.cpp
stream_test.cpp
openssh_fixture.hpp
session_fixture.hpp
sftp_fixture.hpp
sftp_fixture.cpp)
openssh_fixture.hpp)
target_link_libraries(openssh_fixture_
PUBLIC ${Boost_LIBRARIES}
PRIVATE Boost::Process)

add_library(session_fixture_
session_fixture.cpp
session_fixture.hpp)
target_link_libraries(session_fixture_
PUBLIC openssh_fixture_ ssh)

add_library(sftp_fixture_
sftp_fixture.cpp
sftp_fixture.hpp)
target_link_libraries(sftp_fixture_
PUBLIC session_fixture_)

set(INTEGRATION_TESTS
auth_test
filesystem_test
filesystem_construction_test
host_key_test
session_test
input_stream_test
output_stream_test
stream_threading_test
io_stream_test)

set(UNIT_TESTS
knownhost_test.cpp
path_test.cpp)
knownhost_test
path_test)

set(TEST_RUNNER_ARGUMENTS
--result_code=yes --build_info=yes --log_level=test_suite)

set(TEST_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}")

include(CMakeParseArguments)
# ssh_test_suite(SUBJECT test-target [VARIANT suite-variant] SOURCES ...
# LIBRARIES ... [LABELS ...])
# ssh_test_suite(SUBJECT test-target TESTS ... LIBRARIES ... [LABELS ...])
function(SSH_TEST_SUITE)
set(options)
set(oneValueArgs SUBJECT VARIANT)
set(multiValueArgs SOURCES LIBRARIES LABELS)
set(oneValueArgs SUBJECT)
set(multiValueArgs TESTS LIBRARIES LABELS)
cmake_parse_arguments(SSH_TEST_SUITE
"${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if(SSH_TEST_SUITE_VARIANT)
set(_TEST_EXE_NAME
"test-${SSH_TEST_SUITE_SUBJECT}-${SSH_TEST_SUITE_VARIANT}")
else()
set(_TEST_EXE_NAME "test-${SSH_TEST_SUITE_SUBJECT}")
endif()

add_executable(${_TEST_EXE_NAME} module.cpp ${SSH_TEST_SUITE_SOURCES})

target_link_libraries(${_TEST_EXE_NAME}
PRIVATE
${SSH_TEST_SUITE_SUBJECT} ${SSH_TEST_SUITE_LIBRARIES})

add_dependencies(BUILD_ALL_TESTS ${_TEST_EXE_NAME})

add_test(
NAME ${_TEST_EXE_NAME}
COMMAND ${_TEST_EXE_NAME} ${TEST_RUNNER_ARGUMENTS}
WORKING_DIRECTORY "${TEST_DATA_DIR}")

if(MEMORY_LEAKS_ARE_FAILURES)
# Don't hide memory leak detection. The detector can't change the error
# code so the test appears successful otherwise.
set_tests_properties(${_TEST_EXE_NAME} PROPERTIES
FAIL_REGULAR_EXPRESSION "Detected memory leaks")
endif()

if(SSH_TEST_SUITE_LABELS)
set_tests_properties(
${_TEST_EXE_NAME} PROPERTIES LABELS "${SSH_TEST_SUITE_LABELS}")
endif()
endfunction()
foreach(_TEST_NAME ${SSH_TEST_SUITE_TESTS})
set(_TEST_EXE_NAME "test-${SSH_TEST_SUITE_SUBJECT}-${_TEST_NAME}")
set(_TEST_SOURCE_FILE "${_TEST_NAME}.cpp")

hunter_add_package(Boost.Process)
add_executable(${_TEST_EXE_NAME} module.cpp ${_TEST_SOURCE_FILE})

target_link_libraries(${_TEST_EXE_NAME}
PRIVATE ${SSH_TEST_SUITE_SUBJECT} ${SSH_TEST_SUITE_LIBRARIES})

add_dependencies(BUILD_ALL_TESTS ${_TEST_EXE_NAME})

add_test(
NAME ${_TEST_EXE_NAME}
COMMAND ${_TEST_EXE_NAME} ${TEST_RUNNER_ARGUMENTS}
WORKING_DIRECTORY "${TEST_DATA_DIR}")

if(MEMORY_LEAKS_ARE_FAILURES)
# Don't hide memory leak detection. The detector can't change the error
# code so the test appears successful otherwise.
set_tests_properties(${_TEST_EXE_NAME} PROPERTIES
FAIL_REGULAR_EXPRESSION "Detected memory leaks")
endif()

if(SSH_TEST_SUITE_LABELS)
set_tests_properties(
${_TEST_EXE_NAME} PROPERTIES LABELS "${SSH_TEST_SUITE_LABELS}")
endif()
endforeach()
endfunction()

ssh_test_suite(
SUBJECT ssh
SOURCES ${INTEGRATION_TESTS}
LIBRARIES ${Boost_LIBRARIES} Boost::Process
TESTS ${INTEGRATION_TESTS}
LIBRARIES ${Boost_LIBRARIES} openssh_fixture_ session_fixture_ sftp_fixture_
LABELS integration)

ssh_test_suite(
SUBJECT ssh VARIANT unit
SOURCES ${UNIT_TESTS}
TESTS ${UNIT_TESTS}
LIBRARIES ${Boost_LIBRARIES}
LABELS unit)
140 changes: 140 additions & 0 deletions test/ssh/filesystem_construction_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2010, 2013, 2016 Alexander Lamaison

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "session_fixture.hpp"

#include <ssh/filesystem.hpp> // test subject
#include <ssh/stream.hpp>

#include <boost/move/move.hpp>
#include <boost/system/system_error.hpp>
#include <boost/test/unit_test.hpp>

#include <memory> // auto_ptr

using ssh::filesystem::ofstream;
using ssh::filesystem::sftp_filesystem;
using ssh::session;

using boost::move;
using boost::system::system_error;

using test::ssh::session_fixture;

using std::auto_ptr;

BOOST_AUTO_TEST_SUITE(filesystem_construction_test)

BOOST_FIXTURE_TEST_CASE(construct_fail, session_fixture)
{
session& s = test_session();

// Session not authenticated so SFTP not possible
BOOST_CHECK_THROW(s.connect_to_filesystem(), system_error);
}

// This tests the very basic requirements of any sensible relationship between
// a filesystem and a session. It must be possible to create a filesystem
// before moving the session. That's it.
//
// In particular, we destroy the filesystem before moving the object because
// we don't want to test an added requirement that the filesystem's lifetime
// can extend beyond the session's move. Whatever else we might decide the
// semantics of the session-filesystem relationship should be now or in the
// future, this tests must pass. Anything else would mean moving depends on
// what you've used the session for in the past, which would just be broken.
//
// In other words, even the most careful caller would run into trouble
// if this test failed.
BOOST_FIXTURE_TEST_CASE(move_session_after_connecting_filesystem,
session_fixture)
{
session& s = test_session();
s.authenticate_by_key_files(user(), public_key_path(), private_key_path(),
"");

{
sftp_filesystem(s.connect_to_filesystem());
}

session(move(s));
}

// This builds slightly on the previous test by checking that the filesystem
// can be destroyed _after_ the session is moved. It still isn't a test that
// the filesystem is usable afterwards (though we probably want that
// property too), just that the object is valid (can be destroyed).
//
// In an earlier version, the filesystem destructor tried to use the moved
// session causing a crash. It's very hard sometimes to ensure the filesystem
// is destroyed before the exact (non-moved) session it came from, so its
// important we allow destruction to happen after moving the session (but
// before moved-to session is destroyed).
BOOST_FIXTURE_TEST_CASE(move_session_with_live_filesystem_connection,
session_fixture)
{
session& s = test_session();
s.authenticate_by_key_files(user(), public_key_path(), private_key_path(),
"");

sftp_filesystem fs = s.connect_to_filesystem();
session s2(move(s));

// The rules are that the last session must outlive the last FS so moving
// FS to inner scope ensures this
sftp_filesystem(move(fs));
}

// This is the third part of the session-movement tests. It strengthens the
// requirements a bit more to ensure the filesystem is not just valid for
// destruction but also still functions as a filesystem connection.
BOOST_FIXTURE_TEST_CASE(moving_session_leaves_working_filesystem,
session_fixture)
{
session& s = test_session();
s.authenticate_by_key_files(user(), public_key_path(), private_key_path(),
"");

sftp_filesystem fs = s.connect_to_filesystem();
session s2(move(s));

// The rules are that the last session must outlive the last FS so moving
// FS to inner scope ensures this
sftp_filesystem fs2(move(fs));
ofstream(fs2, "/tmp/bob.txt").close();

BOOST_CHECK(exists(fs2, "/tmp/bob.txt"));
}

BOOST_FIXTURE_TEST_CASE(swap_session_with_live_filesystem_connection,
session_fixture)
{
// Both sockets must outlive both session objects
auto_ptr<boost::asio::ip::tcp::socket> socket1(connect_additional_socket());
auto_ptr<boost::asio::ip::tcp::socket> socket2(connect_additional_socket());

session s(socket1->native());
session t(socket2->native());
s.authenticate_by_key_files(user(), public_key_path(), private_key_path(),
"");
t.authenticate_by_key_files(user(), public_key_path(), private_key_path(),
"");

sftp_filesystem fs = s.connect_to_filesystem();

boost::swap(t, s);
}

BOOST_AUTO_TEST_SUITE_END();
Loading

0 comments on commit 6d2a91d

Please sign in to comment.