Repository: celix Updated Branches: refs/heads/develop 061669071 -> ac4babf33
CELIX-408: Initial commit for adding add_runtime command. Also add some usage for running/testing pubsub Project: http://git-wip-us.apache.org/repos/asf/celix/repo Commit: http://git-wip-us.apache.org/repos/asf/celix/commit/97df926c Tree: http://git-wip-us.apache.org/repos/asf/celix/tree/97df926c Diff: http://git-wip-us.apache.org/repos/asf/celix/diff/97df926c Branch: refs/heads/develop Commit: 97df926c2289323379506d47a6095b0182d752b7 Parents: 0616690 Author: Pepijn Noltes <[email protected]> Authored: Sat Apr 8 21:26:39 2017 +0200 Committer: Pepijn Noltes <[email protected]> Committed: Mon Apr 10 22:37:29 2017 +0200 ---------------------------------------------------------------------- cmake/CMakeCelix.cmake | 1 + cmake/cmake_celix/DeployPackaging.cmake | 22 +- cmake/cmake_celix/Runtimes.cmake | 161 +++++++++++++++ cmake/cmake_celix/runtime_common.sh.in | 152 ++++++++++++++ cmake/cmake_celix/runtime_start.sh.in | 26 +++ cmake/cmake_celix/runtime_stop.sh.in | 19 ++ documents/cmake_commands/readme.md | 2 + framework/private/src/bundle_context.c | 2 +- launcher/CMakeLists.txt | 17 ++ launcher/private/src/celix_test_runner.cpp | 73 +++++++ pubsub/CMakeLists.txt | 3 + pubsub/deploy/CMakeLists.txt | 58 ++++++ pubsub/mock/CMakeLists.txt | 8 +- .../private/src/topic_publication.c | 8 +- pubsub/test/CMakeLists.txt | 87 ++++++++ pubsub/test/msg_descriptors/msg.descriptor | 8 + pubsub/test/test/msg.h | 27 +++ pubsub/test/test/sut_activator.c | 112 +++++++++++ pubsub/test/test/tst_activator.cpp | 199 +++++++++++++++++++ 19 files changed, 971 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/CMakeCelix.cmake ---------------------------------------------------------------------- diff --git a/cmake/CMakeCelix.cmake b/cmake/CMakeCelix.cmake index 9ca4de7..8c14577 100644 --- a/cmake/CMakeCelix.cmake +++ b/cmake/CMakeCelix.cmake @@ -26,6 +26,7 @@ include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/Dependencies.cmake) include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/BundlePackaging.cmake) include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/DeployPackaging.cmake) include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/DockerPackaging.cmake) +include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/Runtimes.cmake) include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/ApacheRat.cmake) include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/CodeCoverage.cmake) include(${CELIX_CMAKE_DIRECTORY}/cmake_celix/BuildOptions.cmake) http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/DeployPackaging.cmake ---------------------------------------------------------------------- diff --git a/cmake/cmake_celix/DeployPackaging.cmake b/cmake/cmake_celix/DeployPackaging.cmake index 22e2885..626b7b8 100644 --- a/cmake/cmake_celix/DeployPackaging.cmake +++ b/cmake/cmake_celix/DeployPackaging.cmake @@ -28,24 +28,27 @@ function(add_deploy) list(REMOVE_AT ARGN 0) set(OPTIONS COPY) - set(ONE_VAL_ARGS GROUP NAME LAUNCHER) + set(ONE_VAL_ARGS GROUP NAME LAUNCHER DIR) set(MULTI_VAL_ARGS BUNDLES PROPERTIES) cmake_parse_arguments(DEPLOY "${OPTIONS}" "${ONE_VAL_ARGS}" "${MULTI_VAL_ARGS}" ${ARGN}) ##### Check arguments ##### - if(NOT DEPLOY_NAME) + if (NOT DEPLOY_NAME) set(DEPLOY_NAME "${DEPLOY_TARGET}") - endif() + endif () + if (NOT DEPLOY_DIR) + set(DEPLOY_DIR "${CMAKE_BINARY_DIR}/deploy") + endif () ###### ##### Setting defaults ##### - if(DEPLOY_GROUP) - set(DEPLOY_LOCATION "${CMAKE_BINARY_DIR}/deploy/${DEPLOY_GROUP}/${DEPLOY_NAME}") + if (DEPLOY_GROUP) + set(DEPLOY_LOCATION "${DEPLOY_DIR}/${DEPLOY_GROUP}/${DEPLOY_NAME}") set(DEPLOY_PRINT_NAME "${DEPLOY_GROUP}/${DEPLOY_NAME}") - else() - set(DEPLOY_LOCATION "${CMAKE_BINARY_DIR}/deploy/${DEPLOY_NAME}") + else () + set(DEPLOY_LOCATION "${DEPLOY_DIR}/${DEPLOY_NAME}") set(DEPLOY_PRINT_NAME "${DEPLOY_NAME}") - endif() + endif () ###### @@ -77,6 +80,9 @@ function(add_deploy) #setup dependencies based on timestamp add_custom_command(OUTPUT "${TIMESTAMP_FILE}" COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_LOCATION> + COMMAND chmod +x $<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_LOCATION>/run.sh + COMMAND chmod +x $<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_LOCATION>/release.sh DEPENDS "$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_TARGET_DEPS>" ${DEPLOY_FILE_TARGETS} WORKING_DIRECTORY "${DEPLOY_LOCATION}" COMMENT "Deploying ${DEPLOY_PRINT_NAME}" VERBATIM http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/Runtimes.cmake ---------------------------------------------------------------------- diff --git a/cmake/cmake_celix/Runtimes.cmake b/cmake/cmake_celix/Runtimes.cmake new file mode 100644 index 0000000..14f88eb --- /dev/null +++ b/cmake/cmake_celix/Runtimes.cmake @@ -0,0 +1,161 @@ +add_custom_target(runtimes ALL + DEPENDS "$<TARGET_PROPERTY:runtimes,DEPS>" +) +set_target_properties(runtimes PROPERTIES "DEPS" "") +set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_BINARY_DIR}/runtimes") + +function(add_runtime) + list(GET ARGN 0 RUNTIME_TARGET_NAME) + list(REMOVE_AT ARGN 0) + + set(OPTIONS USE_TERM LOG_TO_FILES) + set(ONE_VAL_ARGS WAIT_FOR NAME GROUP) + set(MULTI_VAL_ARGS DEPLOYMENTS COMMANDS) + cmake_parse_arguments(RUNTIME "${OPTIONS}" "${ONE_VAL_ARGS}" "${MULTI_VAL_ARGS}" ${ARGN}) + + if (NOT RUNTIME_NAME) + set(RUNTIME_NAME ${RUNTIME_TARGET_NAME}) + endif () + if (NOT RUNTIME_GROUP) + set(RUNTIME_LOCATION "${PROJECT_BINARY_DIR}/runtimes/${RUNTIME_NAME}") + else () + set(RUNTIME_LOCATION "${PROJECT_BINARY_DIR}/runtimes/${RUNTIME_GROUP}/${RUNTIME_NAME}") + endif () + set(TIMESTAMP_FILE "${CMAKE_CURRENT_BINARY_DIR}/${RUNTIME_TARGET_NAME}-runtime-timestamp") + + set(START_SCRIPT "$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/start.sh") + set(STOP_SCRIPT "$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/stop.sh") + set(COMMON_SCRIPT "$<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/common.sh") + + add_custom_command(OUTPUT "${TIMESTAMP_FILE}" + COMMAND ${CMAKE_COMMAND} -E touch ${TIMESTAMP_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory $<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION> + COMMAND chmod +x $<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/start.sh + COMMAND chmod +x $<TARGET_PROPERTY:${RUNTIME_TARGET_NAME},RUNTIME_LOCATION>/stop.sh + #TODO DEPENDS "$<TARGET_PROPERTY:${DEPLOY_TARGET},DEPLOY_TARGET_DEPS>" ${DEPLOY_FILE_TARGETS} + DEPENDS ${START_SCRIPT} ${STOP_SCRIPT} ${SETUP_SCRIPT} + WORKING_DIRECTORY "${RUNTIME_LOCATION}" + COMMENT "Creating runtime ${RUNTIME_TARGET_NAME}" VERBATIM + ) + add_custom_target(${RUNTIME_TARGET_NAME} + DEPENDS "${TIMESTAMP_FILE}" + ) + + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_DEPLOYMENTS" "") #deployments that should be runned + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_COMMANDS" "") #command that should be executed + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_NAME" "${RUNTIME_NAME}") #The runtime workdir + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_GROUP" "${RUNTIME_GROUP}") #The runtime workdir + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_LOCATION" "${RUNTIME_LOCATION}") #The runtime workdir + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_USE_TERM" "${RUNTIME_USE_TERM}") #Wether or not the use terminal + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_LOG_TO_FILES" "${RUNTIME_LOG_TO_FILES}") #log to files or std out/err + + #wait for deployment, e.g. the one that control the lifecycle of the runtime. + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_WAIT_FOR_DEPLOYMENT" "") + + #wait for command, e.g. the one that control the lifecycle of the runtime. + set_target_properties(${RUNTIME_TARGET_NAME} PROPERTIES "RUNTIME_WAIT_FOR_COMMAND" "") + + + #replaces @RUNTIME_TARGET_NAME@ + #TODO move to another location + configure_file("${CELIX_CMAKE_DIRECTORY}/cmake_celix/runtime_start.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/start.sh.${RUNTIME_TARGET_NAME}.in.1" @ONLY) + configure_file("${CELIX_CMAKE_DIRECTORY}/cmake_celix/runtime_stop.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/stop.sh.${RUNTIME_TARGET_NAME}.in.1" @ONLY) + configure_file("${CELIX_CMAKE_DIRECTORY}/cmake_celix/runtime_common.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.1" @ONLY) + + + #replaces $<TARGET_PROPERTY:<RUNTIME_NAME>,RUNTIME_DEPLOYMENTS> + file(GENERATE + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.2" + INPUT "${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.1" + ) + file(GENERATE + OUTPUT "${START_SCRIPT}" + INPUT "${CMAKE_CURRENT_BINARY_DIR}/start.sh.${RUNTIME_TARGET_NAME}.in.1" + ) + file(GENERATE + OUTPUT "${STOP_SCRIPT}" + INPUT "${CMAKE_CURRENT_BINARY_DIR}/stop.sh.${RUNTIME_TARGET_NAME}.in.1" + ) + + + #replaces list of $<TARGET_PROPERTY:<DEPLOY_NAME>,DEPLOY_LOCATION>, only needed for common + file(GENERATE + OUTPUT "${COMMON_SCRIPT}" + INPUT "${CMAKE_CURRENT_BINARY_DIR}/common.sh.${RUNTIME_TARGET_NAME}.in.2" + ) + + get_target_property(DEPS runtimes "DEPS") + list(APPEND DEPS "${RUNTIME_TARGET_NAME}") + set_target_properties(runtimes PROPERTIES "DEPS" "${DEPS}") + + runtime_deployments(${RUNTIME_TARGET_NAME} ${RUNTIME_DEPLOYMENTS}) + runtime_commands(${RUNTIME_TARGET_NAME} ${RUNTIME_COMMANDS}) + + if (RUNTIME_WAIT_FOR) + runtime_deployment_wait_for(${RUNTIME_TARGET_NAME} ${RUNTIME_WAIT_FOR}) + endif () + +endfunction() + +function(runtime_use_term) + #0 is runtime TARGET + #1 is BOOL (use xterm) + list(GET ARGN 0 RUNTIME_NAME) + list(GET ARGN 1 USE_TERM) + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_USE_TERM" "${USE_TERM}") +endfunction() + +function(runtime_log_to_files) + #0 is runtime TARGET + #1 is BOOL (log to files) + list(GET ARGN 0 RUNTIME_NAME) + list(GET ARGN 1 LOG_TO_FILES) + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_LOG_TO_FILES" "${LOG_TO_FILES}") +endfunction() + +function(runtime_deployments) + #0 is runtime TARGET + #1..n is deployments + list(GET ARGN 0 RUNTIME_NAME) + list(REMOVE_AT ARGN 0) + + get_target_property(DEPLOYMENTS ${RUNTIME_NAME} "RUNTIME_DEPLOYMENTS") + foreach(DEPLOYMENT IN ITEMS ${ARGN}) + list(APPEND DEPLOYMENTS "$<TARGET_PROPERTY:${DEPLOYMENT},DEPLOY_LOCATION>") + endforeach() + + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_DEPLOYMENTS" "${DEPLOYMENTS}") +endfunction() + +function(runtime_deployment_wait_for) + #0 is runtime TARGET + #1 is deployment TARGET + list(GET ARGN 0 RUNTIME_NAME) + list(GET ARGN 1 DEPLOYMENT) + + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_WAIT_FOR_DEPLOYMENT" "$<TARGET_PROPERTY:${DEPLOYMENT},DEPLOY_LOCATION>") + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_WAIT_FOR_COMMAND" "") +endfunction() + +function(runtime_commands) + #0 is runtime TARGET + #1..n is commands + list(GET ARGN 0 RUNTIME_NAME) + list(REMOVE_AT ARGN 0) + + get_target_property(COMMANDS ${RUNTIME_NAME} "RUNTIME_COMMANDS") + foreach(CMD IN ITEMS ${ARGN}) + list(APPEND COMMANDS ${CMD}) + endforeach() + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_COMMANDS" "${COMMANDS}") +endfunction() + +function(runtime_command_wait_for) + #0 is deploy TARGET + #1 is COMMAND STR + list(GET ARGN 0 RUNTIME_NAME) + list(GET ARGN 1 COMMAND) + + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_WAIT_FOR_COMMAND" "${COMMAND}") + set_target_properties(${RUNTIME_NAME} PROPERTIES "RUNTIME_WAIT_FOR_DEPLOYMENT" "") +endfunction() \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/runtime_common.sh.in ---------------------------------------------------------------------- diff --git a/cmake/cmake_celix/runtime_common.sh.in b/cmake/cmake_celix/runtime_common.sh.in new file mode 100644 index 0000000..e59c6b0 --- /dev/null +++ b/cmake/cmake_celix/runtime_common.sh.in @@ -0,0 +1,152 @@ +#!/bin/sh + +#Locations +BUILD_DIR="${BUILD_DIR:-@PROJECT_BINARY_DIR@}" +RUNTIME_DIR="${RUNTIME_DIR:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOCATION>}" +DEPLOY_DIR="${DEPLOY_DIR:-${BUILD_DIR}/deploy}" + +#Name & Group +RUNTIME_NAME="${RUNTIME_NAME:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_NAME>}" +RUNTIME_GROUP="${RUNTIME_NAME:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_GROUP>}" + +#deployments & commands +DEPLOYMENTS=${DEPLOYMENTS:-"$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_DEPLOYMENTS>, >"} +COMMANDS=${COMMANDS:-"$<JOIN:$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_COMMANDS>, >"} + +#Options +TERM_CMD="${TERM_CMD:-xterm}" +TERM_OPTS="${TERM_OPTS:-}" +USE_TERM="${USE_TERM:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_USE_TERM>}" +RELEASE_SH="${RELEASE_SH:-}" +WAIT_FOR_DEPLOYMENT="${WAIT_FOR_DEPLOYMENT:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_WAIT_FOR_DEPLOYMENT>}" +WAIT_FOR_CMD="${WAIT_FOR_CMD:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_WAIT_FOR_COMMAND>}" +LOG_TO_FILES="${LOG_TO_FILES:-$<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOG_TO_FILES>}" +KILL_OPTS="${KILL_OPTS:-}" + +PIDS="" +WAIT_FOR_PID="" +LOG_SUFFIX=$(date +"%s") +trap stop_all INT + +#clear dirs +function rt_init() { + rm -fr ${RUNTIME_DIR}/run #contains pids, etc + mkdir ${RUNTIME_DIR}/run + if [ ! -e ${RUNTIME_DIR}/logs ] ; then + mkdir ${RUNTIME_DIR}/logs + fi +} + +##functions +function rt_stop_all() { + for PID in ${PIDS}; do + echo "Sending signal to ${PID}" + kill ${KILL_OPTS} ${PID} + done +} + +function rt_stop() { + PIDS=$@ + echo "Stopping pids ${PIDS}" + kill ${KILL_OPTS} ${PIDS} +} + +function rt_run_deployment() { + DEPLOYMENT_DIR=$1 + DEPLOYMENT=$(basename ${DEPLOYMENT_DIR}) + LOG_FILE="${RUNTIME_DIR}/logs/${DEPLOYMENT}-${LOG_SUFFIX}.log" + echo "Running ${DEPLOYMENT}" + cd ${DEPLOYMENT_DIR} #assuming absolute dir + if [ -d .cache ] ; then + echo "Clearing cache" + rm -fr .cache #clear cache + fi + . ./release.sh #run deployment release + if [ "${USE_TERM}" = "TRUE" ] ; then + if [ "${LOG_TO_FILES}" = "TRUE" ] ; then + ${TERM_CMD} ${TERM_OPTS} -e "./${DEPLOYMENT} &> ${LOG_FILE}" & + else + ${TERM_CMD} ${TERM_OPTS} -e "./${DEPLOYMENT}" & + fi + else #run in this shell + if [ "${LOG_TO_FILES}" = "TRUE" ] ; then + ./${DEPLOYMENT} &> ${LOG_FILE} & + else + ./${DEPLOYMENT} & + fi + fi + PID=$! + echo "PID of DEPLOYMENT '${DEPLOYMENT}' is ${PID}" + if [ ! -z "${WAIT_FOR_DEPLOYMENT}" -a "${DEPLOYMENT_DIR}" = "${WAIT_FOR_DEPLOYMENT}" ] ; then + WAIT_FOR_PID=${PID} + echo "${PID}" > ${RUNTIME_DIR}/run/wait_for_pid + else + PIDS="${PID} ${PIDS}" + echo "${PIDS}" > ${RUNTIME_DIR}/run/pids + fi + cd - +} + +function rt_run_cmd() { + CMD="$1" + LOG_FILE="${RUNTIME_DIR}/logs/${CMD}-${LOG_SUFFIX}.log" #TODO only use first word in case of complex command + cd ${RUNTIME_DIR} + if [ "${USE_TERM}" = "TRUE" ] ; then + if [ "${LOG_TO_FILES}" = "TRUE" ] ; then + ${TERM_CMD} ${TERM_OPTS} -e "${CMD} &> ${LOG_FILE}" & + else + ${TERM_CMD} ${TERM_OPTS} -e "${CMD}" & + fi + else + if [ "${LOG_TO_FILES}" = "TRUE" ] ; then + ${CMD} &> \"${LOG_FILE}\" & + else + ${CMD} & + fi + fi + PID=$! + echo "PID of COMMAND '${CMD}' is ${PID}" + if [ ! -z "${WAIT_FOR_CMD}" -a "${CMD}" = "${MWAIT_FOR_CMD}" ] ; then + WAIT_FOR_PID=${PID} + echo "${PID}" > ${RUNTIME_DIR}/run/wait_for_pid + else + PIDS="${PID} ${PIDS}" + echo "${PIDS}" > ${RUNTIME_DIR}/run/pids + fi + cd - +} + +function rt_wait_for() { + RESULT=0 + echo "Waiting for pid ${WAIT_FOR_PID}" + if wait ${WAIT_FOR_PID}; then + echo "${WAIT_FOR_PID} exited normal" + else + echo "${WAIT_FOR_PID} exited with error" + RESULT=1 + fi + + echo "Signalling pids:${PIDS}" + kill ${PIDS} + + for PID in ${PIDS}; do + if wait ${PID}; then + echo "${PID} exited normal" + else + echo "${PID} exited with error" + fi + done + + echo ${RESULT} +} + + +if [ -z "${RELEASE_SH}" ] ; then + true #pass +elif [ -e "${RELEASE_SH}" ]; then #absolute release file + source ${RELEASE_SH} +elif [ -e "${RUNTIME_DIR}/${RELEASE_SH}" ] ; then #release file in runtime dir + source ${RUNTIME_DIR}/${RELEASE_SH} +elif [ -e "${BUILD_DIR}/${RELEASE_SH}" ] ; then #release file in build dir + source ${BUILD_DIR}/${RELEASE_SH} +fi \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/runtime_start.sh.in ---------------------------------------------------------------------- diff --git a/cmake/cmake_celix/runtime_start.sh.in b/cmake/cmake_celix/runtime_start.sh.in new file mode 100644 index 0000000..e7e94f6 --- /dev/null +++ b/cmake/cmake_celix/runtime_start.sh.in @@ -0,0 +1,26 @@ +#!/bin/sh +source $<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOCATION>/common.sh + +echo "Starting runtime ${RUNTIME_NAME}" + +rt_init + +for DEPLOYMENT_DIR in ${DEPLOYMENTS}; do + rt_run_deployment ${DEPLOYMENT_DIR} +done + +for CMD in ${COMMANDS}; do + rt_run_cmd "${CMD}" +done + +echo "PIDS are ${PIDS}." + +if [ ! -z "${WAIT_FOR_PID}" ] ; then + rt_wait_for #sets RESULT + echo "RESULT is ${RESULT}" + exit ${RESULT} +fi + + + + http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/cmake/cmake_celix/runtime_stop.sh.in ---------------------------------------------------------------------- diff --git a/cmake/cmake_celix/runtime_stop.sh.in b/cmake/cmake_celix/runtime_stop.sh.in new file mode 100644 index 0000000..fd7338e --- /dev/null +++ b/cmake/cmake_celix/runtime_stop.sh.in @@ -0,0 +1,19 @@ +#!/bin/sh + +source $<TARGET_PROPERTY:@RUNTIME_TARGET_NAME@,RUNTIME_LOCATION>/common.sh + +#Options +USE_SIGNAL=${USE_SIGNAL:-} + +#TODO parse option to easily select kill -9 + +if [ -e ${RUNTIME_DIR}/run/main_pid ] ; then + MAIN_PID=$(cat ${RUNTIME_DIR}/run/wait_for_pid) + rt_stop ${MAIN_PID} +fi + +if [ -e ${RUNTIME_DIR}/run/pids ] ; then + PIDS=$(cat ${RUNTIME_DIR}/run/pids) + rt_stop ${PIDS} +fi + http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/documents/cmake_commands/readme.md ---------------------------------------------------------------------- diff --git a/documents/cmake_commands/readme.md b/documents/cmake_commands/readme.md index f68eb37..63f8732 100644 --- a/documents/cmake_commands/readme.md +++ b/documents/cmake_commands/readme.md @@ -161,6 +161,7 @@ add_deploy(<deploy_target_name> [GROUP group_name] [NAME deploy_name] [LAUNCHER launcher] + [DIR dir] [BUNDLES <bundle1> <bundle2> ...] [PROPERTIES "prop1=val1" "prop2=val2" ...] ) @@ -179,6 +180,7 @@ If the bundle target is never added CMake will give an error: - If GROUP is provided the deployment will be grouped in the provided group name. - If NAME is provided that name will be used for the deployment dir. Default the deploy target name will be used. - If LAUNCHER is provided that path or target will be used as launcher executable for the deployment. If no LAUNCHER is not provided the celix executable will be used. +- If DIR is provided, the specified dir is used instead of `<cmake_build_dir>/deploy` as deploy dir - If BUNDLES is provided the list of bundles will be added the the generated config.properties for startup. Combined with COPY the bundles will also be copied to a bundles dir. - If PROPERTIES is provided the list of properties will be appended to the generated config.properties http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/framework/private/src/bundle_context.c ---------------------------------------------------------------------- diff --git a/framework/private/src/bundle_context.c b/framework/private/src/bundle_context.c index 7951f87..face85d 100644 --- a/framework/private/src/bundle_context.c +++ b/framework/private/src/bundle_context.c @@ -126,7 +126,7 @@ celix_status_t bundleContext_registerService(bundle_context_pt context, const ch service_registration_pt registration = NULL; celix_status_t status = CELIX_SUCCESS; - if (context != NULL && *service_registration == NULL) { + if (context != NULL) { fw_registerService(context->framework, ®istration, context->bundle, serviceName, svcObj, properties); *service_registration = registration; } else { http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/launcher/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 920d4c0..8bac20e 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -36,4 +36,21 @@ if (LAUNCHER) include_directories("${CURL_INCLUDE_DIRS}") install(TARGETS celix RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT framework) + + find_package(CppUTest QUIET) + if (CPPUTEST_FOUND) + #Test running which start celix and run CppUTest RUN_ALL_TESTS. + #Using this test running it is possible to create bundles containing CppUTests. + add_executable(celix_test_runner + private/src/celix_test_runner.cpp + ) + set_target_properties(celix_test_runner PROPERTIES "INSTALL_RPATH" "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") + target_link_libraries(celix_test_runner + celix_framework + ${CURL_LIBRARIES} + ${CPPUTEST_LIBRARIES} + ${CPPUTEST_EXT_LIBRARIES} + ) + install(TARGETS celix_test_runner RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT framework) + endif () endif (LAUNCHER) http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/launcher/private/src/celix_test_runner.cpp ---------------------------------------------------------------------- diff --git a/launcher/private/src/celix_test_runner.cpp b/launcher/private/src/celix_test_runner.cpp new file mode 100644 index 0000000..d1ea2e6 --- /dev/null +++ b/launcher/private/src/celix_test_runner.cpp @@ -0,0 +1,73 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + + +#include <signal.h> + +#include "celix_launcher.h" + +#include <CppUTest/CommandLineTestRunner.h> + +static void shutdown_framework(int signal); +static void ignore(int signal); + +#define DEFAULT_CONFIG_FILE "config.properties" + +static framework_pt framework = NULL; + +int main(int argc, char *argv[]) { + // Perform some minimal command-line option parsing... + char *cfg = DEFAULT_CONFIG_FILE; + + // Set signal handler + (void) signal(SIGINT, shutdown_framework); + (void) signal(SIGUSR1, ignore); + (void) signal(SIGUSR2, ignore); + + int rc = celixLauncher_launch(cfg, &framework); + if (rc != 0) { + printf("Error starting Celix\n"); + } + + if (rc == 0 && framework != NULL) { + rc = RUN_ALL_TESTS(argc, argv); + + celixLauncher_stop(framework); + celixLauncher_waitForShutdown(framework); + celixLauncher_destroy(framework); + } + + if (rc != 0) { + printf("*** FAILURE ***\n"); + } else { + printf("*** SUCCESS ***\n"); + } + + return rc; +} + +static void shutdown_framework(int signal) { + if (framework != NULL) { + celixLauncher_stop(framework); //NOTE main thread will destroy + } +} + +static void ignore(int signal) { + //ignoring for signal SIGUSR1, SIGUSR2. Can be used to interrupt sleep, etc +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/pubsub/CMakeLists.txt b/pubsub/CMakeLists.txt index 44f3bd1..7ad7677 100644 --- a/pubsub/CMakeLists.txt +++ b/pubsub/CMakeLists.txt @@ -36,6 +36,9 @@ if (PUBSUB) add_subdirectory(deploy) add_subdirectory(keygen) add_subdirectory(mock) + if (ENABLE_TESTING) + add_subdirectory(test) + endif() #install api install(FILES api/pubsub/publisher.h api/pubsub/subscriber.h DESTINATION include/celix/pubsub COMPONENT framework) http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/deploy/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/pubsub/deploy/CMakeLists.txt b/pubsub/deploy/CMakeLists.txt index b35ae14..52fecc9 100644 --- a/pubsub/deploy/CMakeLists.txt +++ b/pubsub/deploy/CMakeLists.txt @@ -15,6 +15,8 @@ # specific language governing permissions and limitations # under the License. +find_program(ETCD_CMD NAMES etcd) +find_program(XTERM_CMD NAMES xterm) # UDP Multicast add_deploy("pubsub_publisher_udp_mc" @@ -54,6 +56,23 @@ add_deploy("pubsub_subscriber2_udp_mc" org.apache.celix.pubsub_serializer.PubSubSerializerJson ) +if (ETCD_CMD AND XTERM_CMD) + #Runtime starting a publish and subscriber for udp mc + add_runtime(pubsub_rt_upd_mc + NAME udp_mc + GROUP pubsub + DEPLOYMENTS + pubsub_publisher_udp_mc + pubsub_subscriber_udp_mc + pubsub_subscriber2_udp_mc + COMMANDS + etcd + USE_TERM + ) +else () + message(WARNING "Cannot create runtime for pubsub because etcd and/or xterm is not installed") +endif () + if (BUILD_PUBSUB_PSA_ZMQ) # Dynamic ZMQ / UDP admin @@ -168,4 +187,43 @@ if (BUILD_PUBSUB_PSA_ZMQ) org.apache.celix.pubsub_serializer.PubSubSerializerJson ) + if (ETCD_CMD AND XTERM_CMD) + #Runtime starting two bundles using both zmq and upd mc pubsub + add_runtime(pubsub_rt_zmq_udpmc_combi + NAME combi + GROUP pubsub + DEPLOYMENTS + pubsub_publisher_zmq + pubsub_subscriber_zmq + pubsub_subscriber_zmq + COMMANDS + etcd + USE_TERM + ) + + #Runtime starting a publish and 2 subscribers for zmq + add_runtime(pubsub_rt_zmq + NAME zmq + GROUP pubsub + DEPLOYMENTS + pubsub_publisher + pubsub_subscriber2_zmq + COMMANDS + etcd + USE_TERM + ) + + #Runtime starting a multipart (multiple message in one send) publish and subscriber for zmq + add_runtime(pubsub_rt_multipart_zmq + NAME zmq_multipart + GROUP pubsub + DEPLOYMENTS + pubsub_mp_subscriber_zmq + pubsub_mp_publisher_zmq + COMMANDS + etcd + USE_TERM + ) + endif () + endif() http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/mock/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/pubsub/mock/CMakeLists.txt b/pubsub/mock/CMakeLists.txt index 09d7b2a..189ddc2 100644 --- a/pubsub/mock/CMakeLists.txt +++ b/pubsub/mock/CMakeLists.txt @@ -23,15 +23,15 @@ if (CPPUTEST_FOUND) api ${CPPUTEST_INCLUDE_DIR} ) - + add_library(celix_pubsubmock STATIC src/publisher_mock.cc - ) + ../test/test/msg.h) target_link_libraries(celix_pubsubmock ${CPPUTEST_LIBRARY}) - + install(TARGETS celix_pubsubmock DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT framework) install(FILES api/pubsub/publisher_mock.h DESTINATION include/celix/pubsub COMPONENT framework) - + if (ENABLE_TESTING) add_executable(pubsubmock_test tst/pubsubmock_test.cc http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c ---------------------------------------------------------------------- diff --git a/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c b/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c index cff5005..aa3faf0 100644 --- a/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c +++ b/pubsub/pubsub_admin_udp_mc/private/src/topic_publication.c @@ -364,6 +364,8 @@ static int pubsub_topicPublicationSend(void* handle, unsigned int msgTypeId, con celixThreadMutex_lock(&(bound->parent->tp_lock)); celixThreadMutex_lock(&(bound->mp_lock)); + //TODO //FIXME -> should use pointer to int as identifier, can be many pointers to int .... + printf("TODO FIX usage of msg id's in the serializer hashmap. This seems wrongly based on pointers to uints!!!!\n"); pubsub_message_type *msgType = hashMap_get(bound->msgTypes, &msgTypeId); int major=0, minor=0; @@ -401,7 +403,11 @@ static int pubsub_topicPublicationSend(void* handle, unsigned int msgTypeId, con free(serializedOutput); } else { - printf("TP: Message %u not supported.",msgTypeId); + if (bound->parent->serializerSvc == NULL) { + printf("TP: Serializer is not set!\n"); + } else { + printf("TP: Message %u not supported.\n",msgTypeId); + } status=-1; } http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/pubsub/test/CMakeLists.txt b/pubsub/test/CMakeLists.txt new file mode 100644 index 0000000..7cd0003 --- /dev/null +++ b/pubsub/test/CMakeLists.txt @@ -0,0 +1,87 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +find_program(ETCD_CMD NAMES etcd) + +find_package(CppUTest REQUIRED) +include_directories(${CPPUTEST_INCLUDE_DIR}) + +include_directories( + ${CMAKE_SOURCE_DIR}/pubsub/api + test +) + +add_bundle(pubsub_sut + #"Vanilla" bundle which is under test + SOURCES + test/sut_activator.c + VERSION 1.0.0 +) +bundle_files(pubsub_sut + msg_descriptors/msg.descriptor + DESTINATION "META-INF/descriptors/messages" +) +add_deploy(pubsub_udpmc_sut + NAME deploy_sut + BUNDLES + org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery + org.apache.celix.pubsub_topology_manager.PubSubTopologyManager + org.apache.celix.pubsub_admin.PubSubAdminUdpMc + #org.apache.celix.pubsub_admin.PubSubAdminZmq + org.apache.celix.pubsub_serializer.PubSubSerializerJson + pubsub_sut + DIR ${PROJECT_BINARY_DIR}/runtimes/test/pubsub/udpmc +) + +add_bundle(pubsub_tst + #Test bundle containing cpputests and uses celix_test_runner launcher instead of the celix launcher + SOURCES + test/tst_activator.cpp + VERSION 1.0.0 +) +bundle_files(pubsub_tst + msg_descriptors/msg.descriptor + DESTINATION "META-INF/descriptors/messages" +) +add_deploy(pubsub_udpmc_tst + NAME deploy_tst + BUNDLES + org.apache.celix.pubsub_discovery.etcd.PubsubDiscovery + org.apache.celix.pubsub_topology_manager.PubSubTopologyManager + org.apache.celix.pubsub_admin.PubSubAdminUdpMc + #org.apache.celix.pubsub_admin.PubSubAdminZmq + org.apache.celix.pubsub_serializer.PubSubSerializerJson + pubsub_tst + DIR ${PROJECT_BINARY_DIR}/runtimes/test/pubsub/udpmc + LAUNCHER celix_test_runner +) + +if (ETCD_CMD) + add_runtime(pubsub_rt_test_udpmc + NAME udpmc + GROUP test/pubsub + DEPLOYMENTS + pubsub_udpmc_sut + pubsub_udpmc_tst + COMMANDS + etcd + WAIT_FOR + pubsub_udpmc_tst + USE_TERM + #LOG_TO_FILES + ) +endif () http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/msg_descriptors/msg.descriptor ---------------------------------------------------------------------- diff --git a/pubsub/test/msg_descriptors/msg.descriptor b/pubsub/test/msg_descriptors/msg.descriptor new file mode 100644 index 0000000..808644c --- /dev/null +++ b/pubsub/test/msg_descriptors/msg.descriptor @@ -0,0 +1,8 @@ +:header +type=message +name=msg +version=1.0.0 +:annotations +:types +:message +{n seqnR} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/test/msg.h ---------------------------------------------------------------------- diff --git a/pubsub/test/test/msg.h b/pubsub/test/test/msg.h new file mode 100644 index 0000000..babfd1f --- /dev/null +++ b/pubsub/test/test/msg.h @@ -0,0 +1,27 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#ifndef MSG_H +#define MSG_H + +typedef struct msg { + int seqNr; +} msg_t; + +#endif //MSG_H http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/test/sut_activator.c ---------------------------------------------------------------------- diff --git a/pubsub/test/test/sut_activator.c b/pubsub/test/test/sut_activator.c new file mode 100644 index 0000000..3e3b33b --- /dev/null +++ b/pubsub/test/test/sut_activator.c @@ -0,0 +1,112 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "bundle_activator.h" +#include "service_tracker.h" + +#include "pubsub/subscriber.h" +#include "pubsub/publisher.h" + +static int sut_receive(void *handle, const char *msgType, unsigned int msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release); +static int sut_pubAdded(void *handle, service_reference_pt reference, void *service); +static int sut_pubRemoved(void *handle, service_reference_pt reference, void *service); + + +struct activator { + pubsub_subscriber_t subSvc; + service_registration_pt reg; + + service_tracker_pt tracker; + + pthread_mutex_t mutex; + pubsub_publisher_t* pubSvc; +}; + +celix_status_t bundleActivator_create(bundle_context_pt context, void **userData) { + struct activator* act = malloc(sizeof(*act)); + *userData = act; + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_start(void * userData, bundle_context_pt context) { + struct activator* act = (struct activator*) userData; + + properties_pt props = properties_create(); + properties_set(props, "pubsub.topic", "ping"); + act->subSvc.handle = act; + act->subSvc.receive = sut_receive; + act->reg = NULL; + bundleContext_registerService(context, PUBSUB_SUBSCRIBER_SERVICE_NAME, &act->subSvc, props, &act->reg); + + const char* filter = "(&(objectClass=pubsub.publisher)(pubsub.topic=pong))"; + service_tracker_customizer_pt customizer = NULL; + serviceTrackerCustomizer_create(act, NULL, sut_pubAdded, NULL, sut_pubRemoved, &customizer); + serviceTracker_createWithFilter(context, filter, customizer, &act->tracker); + serviceTracker_open(act->tracker); + + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_stop(void * userData, bundle_context_pt __attribute__((unused)) context) { + struct activator* act = userData; + serviceTracker_close(act->tracker); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_destroy(void * userData, bundle_context_pt __attribute__((unused)) context) { + struct activator* act = userData; + serviceTracker_destroy(act->tracker); + return CELIX_SUCCESS; +} + +static int sut_receive(void *handle, const char *msgType, unsigned int msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release) { + struct activator* act = handle; + printf("Received msg %s, sending back\n", msgType); + pthread_mutex_lock(&act->mutex); + if (act->pubSvc != NULL) { + unsigned int sendId = 0; + act->pubSvc->localMsgTypeIdForMsgType(act->pubSvc->handle, msgType, &sendId); + act->pubSvc->send(act->pubSvc->handle, sendId, msg); + } + pthread_mutex_unlock(&act->mutex); + return CELIX_SUCCESS; +} + +static int sut_pubAdded(void *handle, service_reference_pt reference, void *service) { + struct activator* act = handle; + pthread_mutex_lock(&act->mutex); + act->pubSvc = service; + pthread_mutex_unlock(&act->mutex); + return CELIX_SUCCESS; + +} + +static int sut_pubRemoved(void *handle, service_reference_pt reference, void *service) { + struct activator* act = handle; + pthread_mutex_lock(&act->mutex); + if (act->pubSvc == service) { + act->pubSvc = NULL; + } + pthread_mutex_unlock(&act->mutex); + return CELIX_SUCCESS; +} + http://git-wip-us.apache.org/repos/asf/celix/blob/97df926c/pubsub/test/test/tst_activator.cpp ---------------------------------------------------------------------- diff --git a/pubsub/test/test/tst_activator.cpp b/pubsub/test/test/tst_activator.cpp new file mode 100644 index 0000000..6d957a0 --- /dev/null +++ b/pubsub/test/test/tst_activator.cpp @@ -0,0 +1,199 @@ +/** + *Licensed to the Apache Software Foundation (ASF) under one + *or more contributor license agreements. See the NOTICE file + *distributed with this work for additional information + *regarding copyright ownership. The ASF licenses this file + *to you under the Apache License, Version 2.0 (the + *"License"); you may not use this file except in compliance + *with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + *Unless required by applicable law or agreed to in writing, + *software distributed under the License is distributed on an + *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + *specific language governing permissions and limitations + *under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "bundle_activator.h" +#include "service_tracker.h" + +#include "pubsub/subscriber.h" +#include "pubsub/publisher.h" + +#include "msg.h" + +#include <CppUTest/TestHarness.h> +#include <CppUTestExt/MockSupport.h> + + + +static int tst_receive(void *handle, const char *msgType, unsigned int msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release); +static int tst_pubAdded(void *handle, service_reference_pt reference, void *service); +static int tst_pubRemoved(void *handle, service_reference_pt reference, void *service); + +#define MSG_NAME "msg" + +struct activator { + pubsub_subscriber_t subSvc; + service_registration_pt reg = nullptr; + + service_tracker_pt tracker = nullptr; + + pthread_mutex_t mutex; //protects below + pubsub_publisher_t* pubSvc = nullptr; + unsigned int msgId = 0; + unsigned int count = 0; + + bool started = false; + +}; + +static struct activator g_act; //global + +celix_status_t bundleActivator_create(__attribute__((unused)) bundle_context_pt context, __attribute__((unused)) void **userData) { + //memset(&g_act, 0, sizeof(g_act)); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_start(__attribute__((unused)) void * userData, bundle_context_pt context) { + properties_pt props = properties_create(); + properties_set(props, "pubsub.topic", "pong"); + g_act.subSvc.handle = &g_act; + g_act.subSvc.receive = tst_receive; + bundleContext_registerService(context, PUBSUB_SUBSCRIBER_SERVICE_NAME, &g_act.subSvc, props, &g_act.reg); + + const char* filter = "(&(objectClass=pubsub.publisher)(pubsub.topic=ping))"; + service_tracker_customizer_pt customizer = NULL; + serviceTrackerCustomizer_create(&g_act, NULL, tst_pubAdded, NULL, tst_pubRemoved, &customizer); + serviceTracker_createWithFilter(context, filter, customizer, &g_act.tracker); + serviceTracker_open(g_act.tracker); + + g_act.started = true; + + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_stop(__attribute__((unused)) void * userData, bundle_context_pt __attribute__((unused)) context) { + serviceTracker_close(g_act.tracker); + return CELIX_SUCCESS; +} + +celix_status_t bundleActivator_destroy(__attribute__((unused)) void * userData, bundle_context_pt __attribute__((unused)) context) { + serviceTracker_destroy(g_act.tracker); + return CELIX_SUCCESS; +} + +static int tst_receive(void *handle, const char *msgType, unsigned int msgTypeId, void *msg, pubsub_multipart_callbacks_t *callbacks, bool *release) { + struct activator* act = static_cast<struct activator*>(handle); + pthread_mutex_lock(&act->mutex); + act->count += 1; + pthread_mutex_unlock(&act->mutex); + return CELIX_SUCCESS; +} + +static int tst_pubAdded(void *handle, service_reference_pt reference, void *service) { + struct activator* act = static_cast<struct activator*>(handle); + pthread_mutex_lock(&act->mutex); + act->pubSvc = static_cast<pubsub_publisher_t*>(service); + act->pubSvc->localMsgTypeIdForMsgType(act->pubSvc->handle, MSG_NAME, &g_act.msgId); + pthread_mutex_unlock(&act->mutex); + return CELIX_SUCCESS; + +} + +static int tst_pubRemoved(void *handle, service_reference_pt reference, void *service) { + struct activator* act = static_cast<struct activator*>(handle); + pthread_mutex_lock(&act->mutex); + if (act->pubSvc == service) { + act->pubSvc = NULL; + } + pthread_mutex_unlock(&act->mutex); + return CELIX_SUCCESS; +} + + +TEST_GROUP(PUBSUB_INT_GROUP) +{ + void setup() { + constexpr int TRIES = 25; + constexpr int TIMEOUT = 1000000; + CHECK_EQUAL(true, g_act.started); + + //check if publisher is available + unsigned int msgId = 0; + for (int i = 0; i < TRIES; ++i) { + pthread_mutex_lock(&g_act.mutex); + msgId = g_act.msgId; + pthread_mutex_unlock(&g_act.mutex); + if (msgId == 0) { + printf("publisher still nullptr / msg Id is still 0, waiting for a while\n"); + usleep(TIMEOUT); + } else { + break; + } + } + CHECK(msgId != 0); + + //check if message are returned + msg_t initMsg; + initMsg.seqNr = 0; + for (int i = 0; i < TRIES; ++i) { + pthread_mutex_lock(&g_act.mutex); + g_act.pubSvc->send(g_act.pubSvc->handle, g_act.msgId, &initMsg); + pthread_mutex_unlock(&g_act.mutex); + usleep(TIMEOUT); + pthread_mutex_lock(&g_act.mutex); + int count = g_act.count; + pthread_mutex_unlock(&g_act.mutex); + if (count > 0) { + break; + } else { + printf("No return message received, waiting for a while\n"); + } + } + } + + void teardown() { + //nop + } +}; + +TEST(PUBSUB_INT_GROUP, sendRecvTest) { + g_act.count = 0; + constexpr int COUNT = 50; + msg_t msg; + for (int i = 0; i < COUNT; ++i) { + msg.seqNr = i; + pthread_mutex_lock(&g_act.mutex); + g_act.pubSvc->send(g_act.pubSvc->handle, g_act.msgId, &msg); + pthread_mutex_unlock(&g_act.mutex); + usleep(100000); + } + + constexpr int TRIES = 25; + constexpr int TIMEOUT = 250000; + for (int i = 0; i < TRIES; ++i) { + pthread_mutex_lock(&g_act.mutex); + int count = g_act.count; + pthread_mutex_unlock(&g_act.mutex); + if (count == COUNT) { + break; + } else { + printf("Current count is %i, should be %i. Waiting a little\n", count, COUNT); + usleep(TIMEOUT); + } + } + + pthread_mutex_lock(&g_act.mutex); + int count = g_act.count; + pthread_mutex_unlock(&g_act.mutex); + CHECK_EQUAL(COUNT, count); +} \ No newline at end of file
